วิธีการเรียกใช้งาน Gulp ตามลำดับหนึ่ง ๆ


398

ในตัวอย่างเช่นนี้:

gulp.task "coffee", ->
    gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean",->
    gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"

ในdevelopภารกิจที่ฉันต้องการเรียกใช้cleanและหลังจากเสร็จแล้วให้เรียกใช้coffeeและเมื่อเสร็จแล้วให้เรียกใช้อย่างอื่น แต่ฉันไม่สามารถเข้าใจได้ ชิ้นนี้ไม่ทำงาน กรุณาแนะนำ


10
โมดูล npm ที่ทำงานตามลำดับแก้ไขปัญหานี้ได้ในขณะนี้ - คำตอบอื่น ๆ ทั้งหมดไม่เกี่ยวข้อง - ดูคำตอบของ OverZealous ด้านล่าง
danday74

1
Gulp 4.0 รองรับการรันภารกิจตามลำดับทำให้run-sequenceล้าสมัย - ดูคำตอบของ massanishi ด้านล่าง
Forivin

Gulp4 แบ่งสิ่งต่าง ๆ มากกว่าที่จะแก้ไขดูเหมือนว่า หลังจากต่อสู้กับมันสองสามชั่วโมงฉันกลับไปที่ 3.9.1 ฉันรู้ว่าเวอร์ชันหลักสามารถ / จะแบ่ง backcompat แต่ด้วยข้อความแสดงข้อผิดพลาดที่เป็นความลับและไร้ประโยชน์ฉันก็ไม่ขอบคุณ v4 ยังไม่พร้อม
วันเสาร์ที่ Thiru

คำตอบ:


121

ยังไม่ได้วางจำหน่ายอย่างเป็นทางการ แต่ Gulp 4.0 ที่มาถึงช่วยให้คุณทำงานประสานกับ gulp.series ได้อย่างง่ายดาย คุณสามารถทำได้เช่นนี้:

gulp.task('develop', gulp.series('clean', 'coffee'))

ฉันพบโพสต์บล็อกที่ดีซึ่งแนะนำวิธีอัปเกรดและใช้ประโยชน์จากคุณสมบัติที่เป็นระเบียบเหล่านั้น: การ ย้ายไปยังอึก 4 ตามตัวอย่าง


3
วิธีการเลือกสำหรับผู้มาใหม่ทั้งหมด พวกเขาควรเริ่มต้นด้วยอึก 4 ข้ามทั้งหมด 3. * ความยุ่งยากและ antipatterns ที่หลากหลาย
metalim

187
ปี 2017 และพวกเขายังไม่ได้แนะนำ ยิ่งใหญ่
Tomasz Mularczyk

14
ฉันไม่เห็นประเด็นจริงๆ หากคุณต้องการให้ A รันเฉพาะหลังจากรัน B เท่านั้น A จึงขึ้นอยู่กับ B ทำไมคุณไม่ระบุเพียงว่า B นั้นขึ้นอยู่กับ A gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);
musicin3d

3
@ musicin3d สิ่งที่คุณพูดว่าใช้งานได้ แต่คุณกำลังมีข้อผูกมัดหนึ่งงานที่จำเป็นต่อหน้าที่แล้ว ตัวอย่างเช่นฉันต้องการที่จะสามารถสร้างได้โดยไม่ต้องขยิบตาก่อนเสมอ มันเป็นทางออกที่ดีกว่าที่จะมีงานอิสระและตัดสินใจสั่งการดำเนินการด้วยเครื่องมือภายนอก
AxeEffect

11
2018 ของมันและในที่สุดพวกเขาก็แนะนำมัน ยิ่งใหญ่
dargmuesli

411

โดยค่าเริ่มต้นอึกเรียกใช้งานพร้อมกันเว้นแต่พวกเขามีการอ้างอิงที่ชัดเจน สิ่งนี้ไม่ได้มีประโยชน์มากสำหรับงานอย่างcleanที่คุณไม่ต้องการพึ่งพา แต่คุณต้องการให้ทำงานก่อนทุกอย่าง

ผมเขียนปลั๊กอินโดยเฉพาะการแก้ไขปัญหานี้ด้วยอึก หลังจากติดตั้งแล้วให้ใช้ดังนี้:run-sequence

var runSequence = require('run-sequence');

gulp.task('develop', function(done) {
    runSequence('clean', 'coffee', function() {
        console.log('Run something else');
        done();
    });
});

คุณสามารถอ่านคำแนะนำทั้งหมดในแพ็คเกจ README - มันยังรองรับการทำงานบางอย่างพร้อมกัน

โปรดทราบว่าสิ่งนี้จะได้รับการแก้ไข (อย่างมีประสิทธิภาพ) ในการปล่อยครั้งใหญ่ครั้งต่อไปเนื่องจากพวกเขากำลังกำจัดการสั่งซื้อการพึ่งพาอัตโนมัติโดยสมบูรณ์และมีเครื่องมือที่คล้ายกันrun-sequenceเพื่อให้คุณสามารถระบุลำดับการเรียกใช้ด้วยตนเองตามที่คุณต้องการ

อย่างไรก็ตามนั่นเป็นการเปลี่ยนแปลงครั้งสำคัญดังนั้นจึงไม่มีเหตุผลที่จะต้องรอเมื่อคุณสามารถใช้งานได้run-sequenceในวันนี้


2
@OverZealous ขอบคุณสำหรับปลั๊กอิน! Btw gulp-cleanปลั๊กอินไม่ได้ติดตั้ง Streams 2 ดังนั้นจึงมีปัญหาในการทำงานเป็นการอ้างอิง สิ่งนี้ได้รับการแก้ไขตั้งแต่รุ่นวางจำหน่าย 0.3.0 เพื่อนร่วมงานของฉันส่ง PR เพื่อทำการแปลง
knownasilya

3
@Indolering ฟังก์ชันการพึ่งพางานในตัวไม่สามารถแก้ไขสถานการณ์นี้ได้ ภารกิจที่ขึ้นต่อกันจะทำงานอยู่ตลอดเวลา: ไม่มีวิธีการรันงานสองอย่างติดกันภายในบางครั้ง แต่ไม่ใช่ทุกครั้ง run-sequenceแก้ไขส่วนสำคัญของการทำงานที่ขาดหายไปในอึก
OverZealous

2
นอกจากนี้การพึ่งพางานไม่ใช่โซลูชันที่สมบูรณ์ ว่าฉันมีสองงานอึกที่เรียกใช้การทดสอบโดยใช้ฐานข้อมูล ทั้งสองไม่ขึ้นอยู่กับคนอื่น แต่ฉันไม่ต้องการให้ทั้งสองคนทำงานในเวลาเดียวกันเพราะทั้งคู่ต้องใช้ฐานข้อมูล
peterjwest

3
โมดูลที่น่าตื่นตาตื่นใจ - นี่เป็นคำอธิบายที่ดีว่าทำไมจึงมีความจำเป็น - blog.mdnbar.com/gulp-for-simple-build-proccess - นี่ควรเป็นคำตอบที่ได้รับการยอมรับ
danday74

5
ฉันขอขอบคุณที่คุณได้แก้ปัญหาสำหรับเรื่องนี้ แต่มันไร้สาระที่เราต้องใช้เครื่องมือเพิ่มเติมเพื่อให้ได้การดำเนินการตามลำดับ การดำเนินการตามลำดับควรเป็นค่าเริ่มต้นหรืออย่างน้อยก็ง่ายที่จะทำ Makefiles มีการดำเนินการตามลำดับเป็นเวลา 40 ปี ระบบนิเวศของ JS ทำให้ฉันป่วย node_modules 73 เมกะไบต์เพื่อรวบรวมโครงการสำเร็จรูปที่ไม่มีคุณสมบัติใด ๆ และยังไม่รวมความสามารถในการดำเนินการตามลำดับ ระบบปฏิบัติการเหมาะสมในพื้นที่ขนาดเล็กลงและมีเมล็ดและไดรเวอร์ FFS
joonas.fi

371

ทางออกที่ดีสำหรับปัญหานี้สามารถพบได้ในเอกสารอึกซึ่งสามารถพบได้ที่นี่

var gulp = require('gulp');

// takes in a callback so the engine knows when it'll be done
gulp.task('one', function(cb) {
  // do stuff -- async or otherwise
  cb(err); // if err is not null and not undefined, the orchestration will stop, and 'two' will not run
});

// identifies a dependent task must be complete before this one begins
gulp.task('two', ['one'], function() {
  // task 'one' is done now
});

gulp.task('default', ['one', 'two']);
// alternatively: gulp.task('default', ['two']);

6
ด้วยเหตุผลบางอย่างที่ฉันReferenceError: err is not definedพยายามเรียกใช้ในgulp-compassภารกิจฉันจะทำบางสิ่งบางอย่างหายไปหรือไม่
waffl

11
@waffl ตัวอย่างนี้ใช้การโทรกลับซึ่งไม่ใช่วิธีเดียวในการทำเช่นนี้ ตามเอกสารคุณยังสามารถ "คืนสัญญาหรือสตรีมที่เอ็นจิ้นควรรอที่จะแก้ไขหรือสิ้นสุดตามลำดับ" ดังนั้นหากคุณคืนค่ากระแสข้อมูลในงานที่หนึ่งเช่นreturn gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');กุญแจสำคัญคือการระบุงานที่ขึ้นอยู่กับเมื่อกำหนดงานที่สอง: gulp.task('two', ['one'], function() {... งานที่สองตอนนี้จะรอให้งานหนึ่งที่จะจบก่อนที่จะทำงาน
esvendsen

24
สิ่งนี้จะสร้างคลัปแน่นระหว่าง 'หนึ่ง' และ 'สอง' ถ้าคุณต้องการเรียกใช้ 'สอง' โดยไม่เรียกใช้ 'หนึ่ง'
wilk

5
คุณกำหนดงานใหม่โดยไม่ต้องพึ่งพา?
Mathieu Borderé

8
ต้องการงานสองงานเพื่อเรียกใช้ตามลำดับแสดงถึงการมีเพศสัมพันธ์อย่างแน่นหนา
Ringo

56

ฉันสร้างแอป node / gulp โดยใช้generator-gulp-webapp Yeoman generator มันจัดการ "ปริศนาที่สะอาด" ด้วยวิธีนี้ (แปลไปยังงานดั้งเดิมที่กล่าวถึงในคำถาม):

gulp.task('develop', ['clean'], function () {
  gulp.start('coffee');
});

2
นี่คือสิ่งที่ฉันต้องการ (และง่ายมาก) มันพูดถึงสถานการณ์ที่ฉันต้องทำบางสิ่งบางอย่างเช่น clean as dependency ก่อนหน้านี้เพื่อสร้าง dependencies โดยไม่ต้องตั้งค่า clean เป็นการพึ่งพางานเหล่านั้น PS: ข้อมูลเกี่ยวกับ gulp.start () bit - caveat emptor: github.com/gulpjs/gulp/issues/426
Jaans

นั่นทำให้รู้สึก; การเรียกกลับหลังจากงานหลัก (และเป็นงานที่ต้องพึ่งพา) เสร็จสมบูรณ์ ขอบคุณ
markau

4
หากมีคนสงสัยว่าทำไมไม่มีเอกสารอย่างเป็นทางการสำหรับgulp.start()คำตอบนี้จากสมาชิกอึกอธิบายว่า: gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it(ที่มา: github.com/gulpjs/gulp/issues/426#issuecomment-41208007 )
thybzi

1
ในกรณีนี้ฉันจะตรวจจับcoffeeงานนั้นเสร็จได้อย่างไร หากฉันไม่พบมันdevelopงานจะเสร็จเร็วกว่านี้coffee
thybzi

ได้รับคำตอบจากrun-sequenceซอร์สโค้ดแล้ว: gulp.on('task_stop'). ดูรายละเอียดเพิ่มเติมสำหรับคำตอบเพิ่มเติมได้ที่: stackoverflow.com/a/38818657/3027390
thybzi

32

run-sequenceเป็นวิธีที่ชัดเจนที่สุด (อย่างน้อยก็จนกว่า Gulp 4.0 จะวางจำหน่าย)

ด้วย run-sequenceงานของคุณจะเป็นดังนี้:

var sequence = require('run-sequence');
/* ... */
gulp.task('develop', function (done) {
    sequence('clean', 'coffee', done);
});

แต่ถ้าคุณ (ด้วยเหตุผลบางอย่าง) ไม่ต้องการใช้gulp.startวิธีการจะช่วยให้ :

gulp.task('develop', ['clean'], function (done) {
    gulp.on('task_stop', function (event) {
        if (event.task === 'coffee') {
            done();
        }
    });
    gulp.start('coffee');
});

หมายเหตุ: หากคุณเพิ่งเริ่มงานโดยไม่ฟังผลลัพธ์developงานจะเสร็จสิ้นเร็วกว่าcoffeeและอาจทำให้สับสน

คุณอาจลบผู้ฟังเหตุการณ์เมื่อไม่ต้องการ

gulp.task('develop', ['clean'], function (done) {
    function onFinish(event) {
        if (event.task === 'coffee') {
            gulp.removeListener('task_stop', onFinish);
            done();
        }
    }
    gulp.on('task_stop', onFinish);
    gulp.start('coffee');
});

พิจารณาว่ายังมีtask_errเหตุการณ์ที่คุณอาจต้องการฟัง task_stopถูกเรียกใช้เมื่อเสร็จสิ้นการสำเร็จขณะที่task_errปรากฏขึ้นเมื่อมีข้อผิดพลาดบางอย่าง

gulp.start()นอกจากนี้คุณยังอาจสงสัยว่าทำไมไม่มีเอกสารอย่างเป็นทางการสำหรับ คำตอบจากสมาชิกอึกนี้อธิบายถึงสิ่งต่าง ๆ :

gulp.start ไม่มีจุดประสงค์ในการทำเอกสารเพราะสามารถนำไปสู่การสร้างไฟล์ที่ซับซ้อนและเราไม่ต้องการให้คนใช้งาน

(ที่มา: https://github.com/gulpjs/gulp/issues/426#issuecomment-41208007 )


สองกาแฟกับผู้ชายคนนี้! การแก้ปัญหาด้วยการลบผู้ฟังทำงานได้อย่างสมบูรณ์แบบ!
daniel.bavrin

นี่คือคำตอบจริงๆหรือเพียงแค่ "อึก 4" ลำดับการรันนั้นแข็งแกร่ง
LAdams87

26

ตามเอกสารอึก:

งานของคุณทำงานก่อนที่การอ้างอิงจะเสร็จสมบูรณ์หรือไม่ ตรวจสอบให้แน่ใจว่างานการพึ่งพาของคุณนั้นถูกต้องโดยใช้คำแนะนำในการเรียกใช้ async: ใช้ในการติดต่อกลับหรือส่งคืนสัญญาหรือสตรีมเหตุการณ์

ในการรันลำดับงานของคุณพร้อมกัน:

  1. ส่งคืนสตรีมเหตุการณ์ (เช่นgulp.src) gulp.taskเพื่อแจ้งภารกิจเมื่อสตรีมสิ้นสุด
  2. gulp.taskงานประกาศการอ้างอิงในอาร์กิวเมนต์ที่สองของ

ดูรหัสที่แก้ไข:

gulp.task "coffee", ->
    return gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean", ['coffee'], ->
      return gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"

4
นี่ควรเป็นคำตอบที่ถูกต้อง! งานที่กลับมาทำอุบาย! ขอบคุณชาย
Dzoukr

10

ฉันมีปัญหาเดียวกันนี้อย่างแน่นอนและการแก้ปัญหากลายเป็นเรื่องง่ายสำหรับฉัน โดยทั่วไปเปลี่ยนรหัสของคุณเป็นสิ่งต่อไปนี้และควรใช้งานได้ หมายเหตุ: ผลตอบแทนก่อน gulp.src สร้างความแตกต่างให้ฉันทั้งหมด

gulp.task "coffee", ->
    return gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean",->
    return gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"

ขอบคุณสำหรับข้อความที่ส่งคืน! พยายามที่จะคิดออกว่าทำไมอึกจึงทำสิ่งที่ไม่เป็นระเบียบ
Andrew F

นี่ควรเป็นคำตอบที่ถูกต้องเพื่อหลีกเลี่ยงข้อต่อระหว่างงาน ทำได้ดี. gulp.series ที่มีอยู่ใน 4.0 อาจเป็นคำตอบที่ดีที่สุด แต่ ณ วันนี้ 4.0 ไม่สามารถใช้ได้
wilk

การพัฒนาอึกจะทำงานที่สะอาดหรือกาแฟก่อน
scape

8

ลองใช้วิธีแก้ปัญหาที่เสนอทั้งหมดดูเหมือนว่าจะมีปัญหาของตนเอง

หากคุณมองเข้าไปในแหล่ง Orchestrator โดยเฉพาะอย่างยิ่ง .start()ใช้งานคุณจะเห็นว่าหากพารามิเตอร์สุดท้ายเป็นฟังก์ชั่นมันจะถือว่ามันเป็นโทรกลับ

ฉันเขียนตัวอย่างนี้สำหรับงานของฉัน:

  gulp.task( 'task1', () => console.log(a) )
  gulp.task( 'task2', () => console.log(a) )
  gulp.task( 'task3', () => console.log(a) )
  gulp.task( 'task4', () => console.log(a) )
  gulp.task( 'task5', () => console.log(a) )

  function runSequential( tasks ) {
    if( !tasks || tasks.length <= 0 ) return;

    const task = tasks[0];
    gulp.start( task, () => {
        console.log( `${task} finished` );
        runSequential( tasks.slice(1) );
    } );
  }
  gulp.task( "run-all", () => runSequential([ "task1", "task2", "task3", "task4", "task5" ));

4

ฉันกำลังค้นหาคำตอบนี้อยู่พักหนึ่ง ตอนนี้ฉันได้รับมันในเอกสารอึกอย่างเป็นทางการ

หากคุณต้องการทำงานอึกเมื่องานชิ้นสุดท้ายเสร็จสิ้นคุณจะต้องส่งกระแสข้อมูลกลับมา:

gulp.task('wiredep', ['dev-jade'], function () {
    var stream = gulp.src(paths.output + '*.html')
        .pipe($.wiredep())
        .pipe(gulp.dest(paths.output));

    return stream; // execute next task when this is completed
});

// First will execute and complete wiredep task
gulp.task('prod-jade', ['wiredep'], function() {
    gulp.src(paths.output + '**/*.html')
        .pipe($.minifyHtml())
        .pipe(gulp.dest(paths.output));
});


3

เพียงทำการcoffeeพึ่งพาcleanและdevelopขึ้นอยู่กับcoffee:

gulp.task('coffee', ['clean'], function(){...});
gulp.task('develop', ['coffee'], function(){...});

ส่งอยู่ในขณะนี้อนุกรม: clean→การ→การcoffee developโปรดทราบว่าcleanการนำไปใช้งานและcoffeeการนำไปใช้งานนั้นต้องยอมรับการเรียกกลับ"ดังนั้นเครื่องมือจะรู้ว่าเมื่อใดจะเสร็จสิ้น" :

gulp.task('clean', function(callback){
  del(['dist/*'], callback);
});

โดยสรุปด้านล่างเป็นรูปแบบอึกแบบง่ายสำหรับซิงโครcleanนัสตามด้วยการพึ่งพาการสร้างแบบอะซิงโครนัส :

//build sub-tasks
gulp.task('bar', ['clean'], function(){...});
gulp.task('foo', ['clean'], function(){...});
gulp.task('baz', ['clean'], function(){...});
...

//main build task
gulp.task('build', ['foo', 'baz', 'bar', ...], function(){...})

อึกฉลาดพอที่จะเรียกcleanว่าครั้งเดียวต่อbuildไม่ว่าวิธีการที่หลายbuild's cleanอ้างอิงขึ้นอยู่กับ ดังที่เขียนไว้ด้านบนcleanเป็นอุปสรรคในการซิงโครไนซ์จากนั้นการbuildพึ่งพาทั้งหมดทำงานในแบบขนานจากนั้นbuildเรียกใช้


3

สำหรับฉันมันไม่ได้ใช้งานการลดขนาดหลังจากการต่อข้อมูลตามที่คาดว่าจะมีการต่อข้อมูลเข้าด้วยกันและมันไม่ได้ถูกสร้างขึ้นในบางครั้ง

ฉันพยายามเพิ่มงานเริ่มต้นตามลำดับการดำเนินการและไม่ทำงาน มันทำงานหลังจากเพิ่มเพียงแค่returnสำหรับแต่ละงานและรับ minification ภายในgulp.start()เช่นด้านล่าง

/**
* Concatenate JavaScripts
*/
gulp.task('concat-js', function(){
    return gulp.src([
        'js/jquery.js',
        'js/jquery-ui.js',
        'js/bootstrap.js',
        'js/jquery.onepage-scroll.js',
        'js/script.js'])
    .pipe(maps.init())
    .pipe(concat('ux.js'))
    .pipe(maps.write('./'))
    .pipe(gulp.dest('dist/js'));
});

/**
* Minify JavaScript
*/
gulp.task('minify-js', function(){
    return gulp.src('dist/js/ux.js')
    .pipe(uglify())
    .pipe(rename('ux.min.js'))
    .pipe(gulp.dest('dist/js'));
});

gulp.task('concat', ['concat-js'], function(){
   gulp.start('minify-js');
});

gulp.task('default',['concat']); 

แหล่งที่มาhttp://schickling.me/synchronous-tasks-gulp/


2

อึกและโหนดใช้สัญญา

ดังนั้นคุณสามารถทำสิ่งนี้:

// ... require gulp, del, etc

function cleanTask() {
  return del('./dist/');
}

function bundleVendorsTask() {
  return gulp.src([...])
    .pipe(...)
    .pipe(gulp.dest('...'));
}

function bundleAppTask() {
  return gulp.src([...])
    .pipe(...)
    .pipe(gulp.dest('...'));
}

function tarTask() {
  return gulp.src([...])
    .pipe(...)
    .pipe(gulp.dest('...'));
}

gulp.task('deploy', function deployTask() {
  // 1. Run the clean task
  cleanTask().then(function () {
    // 2. Clean is complete. Now run two tasks in parallel
    Promise.all([
      bundleVendorsTask(),
      bundleAppTask()
    ]).then(function () {
      // 3. Two tasks are complete, now run the final task.
      tarTask();
    });
  });
});

หากคุณคืนค่า gulp stream คุณสามารถใช้then()วิธีเพิ่ม callback หรือคุณสามารถใช้ Node ของ Native Promiseเพื่อสร้างสัญญาของคุณเอง ที่นี่ฉันPromise.all()เคยมีการโทรกลับหนึ่งครั้งที่ไฟไหม้เมื่อสัญญาทั้งหมดแก้ไขได้


-8

ลองแฮ็คนี้ :-) Gulp v3.x Hack for Async bug

ฉันลองใช้วิธี "ทางการ" ทั้งหมดใน Readme พวกเขาไม่ได้ทำงานให้ฉัน คุณยังสามารถอัพเกรดเป็นอึก 4.x แต่ฉันขอแนะนำให้คุณอย่าทำลายมันมาก คุณสามารถใช้สัญญา js จริง ๆ แต่เดี๋ยวก่อนนี่คือรวดเร็วสกปรกง่าย :-) เป็นหลักคุณใช้:

var wait = 0; // flag to signal thread that task is done
if(wait == 0) setTimeout(... // sleep and let nodejs schedule other threads

ตรวจสอบโพสต์!


มีวิธีที่ดีกว่าในการแก้ปัญหาโดยใช้ setTimeout ไม่เหมาะสม คุณไม่รู้แน่ชัดว่างานจะต้องใช้เวลาเท่าไร
Reginaldo Camargo Ribeiro

คุณควรคิดก่อนที่จะเขียนใด ๆ PFF รหัส
DDD
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.