เผยแพร่ จัดส่ง และติดตั้ง JavaScript ที่ทันสมัย เพื่อให้แอปพลิเคชันรวดเร็วขึ้น

ปรับปรุงประสิทธิภาพโดยการเปิดทรัพยากร Dependency และเอาต์พุต JavaScript ที่ทันสมัย

เบราว์เซอร์กว่า 90% สามารถเรียกใช้ JavaScript ที่ทันสมัย แต่ ความแพร่หลายของ JavaScript แบบเดิมยังคงเป็นแหล่งที่มาขนาดใหญ่ของปัญหาด้านประสิทธิภาพ บนเว็บวันนี้

JavaScript สมัยใหม่

JavaScript สมัยใหม่ไม่มีลักษณะเป็นโค้ดที่เขียนด้วย ECMAScript ที่เฉพาะเจาะจง เวอร์ชันที่กำหนด แต่อยู่ในรูปแบบไวยากรณ์ที่สนับสนุนโดยรุ่นสมัยใหม่ทั้งหมด เบราว์เซอร์ เว็บเบราว์เซอร์สมัยใหม่ เช่น Chrome, Edge, Firefox และ Safari กว่า 90% ของตลาดเบราว์เซอร์ และ เบราว์เซอร์ต่างๆ ที่อาศัยเครื่องมือแสดงผลพื้นฐานเดียวกันจะประกอบเป็น เพิ่มเติมอีก 5% ซึ่งหมายความว่า 95% ของการเข้าชมเว็บทั่วโลกมาจากเบราว์เซอร์ ที่รองรับคุณลักษณะภาษา JavaScript ที่ใช้อย่างแพร่หลายที่สุดตั้งแต่ ปี รวมถึง:

  • หมวดหมู่ (ES2015)
  • ฟังก์ชันลูกศร (ES2015)
  • เครื่องกำเนิดไฟฟ้า (ES2015)
  • ขอบเขตของการบล็อก (ES2015)
  • การทำลายโครงสร้าง (ES2015)
  • พารามิเตอร์ส่วนที่เหลือและสเปรด (ES2015)
  • ชวเลขของออบเจ็กต์ (ES2015)
  • ไม่พร้อมกัน/รอ (ES2017)

โดยทั่วไปแล้วฟีเจอร์ในข้อกำหนดภาษาเวอร์ชันใหม่จะมีข้อกำหนดน้อยกว่า การสนับสนุนที่สอดคล้องกันในเบราว์เซอร์สมัยใหม่ ตัวอย่างเช่น หลายรายการ ES2020 และ ES2021 ได้รับการสนับสนุนใน 70% ของตลาดเบราว์เซอร์เท่านั้น และยังคงโดยส่วนใหญ่ เบราว์เซอร์แต่ยังไม่เพียงพอที่จะใช้งานคุณลักษณะเหล่านั้นโดยตรงได้อย่างปลอดภัย ช่วงเวลานี้ หมายความว่าแม้ "สมัยใหม่" JavaScript กำลังเดินหน้ากำหนดเป้าหมาย โดย ES2017 ได้ ความสามารถในการใช้งานร่วมกันของเบราว์เซอร์ที่หลากหลายที่สุด ในขณะเดียวกันก็มีฟีเจอร์ไวยากรณ์สมัยใหม่ที่ใช้กันโดยทั่วไปด้วย กล่าวคือ ES2017 ใกล้เคียงกับไวยากรณ์สมัยใหม่มากที่สุดในปัจจุบัน

JavaScript เดิม

JavaScript แบบเดิมคือโค้ดที่หลีกเลี่ยงการใช้ภาษาข้างต้นทั้งหมดโดยเฉพาะ ใหม่ๆ นักพัฒนาซอฟต์แวร์ส่วนใหญ่เขียนซอร์สโค้ดโดยใช้ไวยากรณ์สมัยใหม่ แต่ รวบรวมทุกอย่างเป็นไวยากรณ์แบบเดิมเพื่อเพิ่มการรองรับเบราว์เซอร์ กำลังคอมไพล์ ไวยากรณ์เดิมจะเพิ่มการสนับสนุนเบราว์เซอร์ แต่ผลกระทบมักจะ น้อยกว่าที่เราคิด ในหลายกรณี การสนับสนุนจะเพิ่มขึ้นจากประมาณ 95% ถึง 98% ในขณะที่มีค่าใช้จ่ายสูง:

  • โดยปกติแล้ว JavaScript แบบเดิมมีขนาดใหญ่กว่าและช้ากว่าประมาณ 20% รหัสสมัยใหม่ที่เทียบเท่ากัน ข้อบกพร่องของเครื่องมือและการกำหนดค่าที่ไม่ถูกต้องบ่อยครั้ง ขยายช่องว่างนี้ให้กว้างขึ้นอีก

  • ไลบรารีที่ติดตั้งคิดเป็น 90% ของเวอร์ชันที่ใช้งานจริงทั่วไป โค้ด JavaScript โค้ดไลบรารีต้องใช้ JavaScript แบบเดิมสูงขึ้นไปอีก ค่าใช้จ่ายจาก Polyfill และความซ้ำซ้อนของตัวช่วยที่ควรหลีกเลี่ยงได้ โดยการเผยแพร่โค้ดสมัยใหม่

JavaScript สมัยใหม่บน npm

เมื่อเร็วๆ นี้ Node.js ได้ทำให้ฟิลด์ "exports" เป็นมาตรฐานเพื่อกำหนด จุดแรกเข้าสำหรับแพ็กเกจ

{
  "exports": "./index.js"
}

โมดูลที่อ้างอิงโดยช่อง "exports" หมายถึงเวอร์ชันโหนดอย่างน้อย 12.8 ซึ่งรองรับ ES2019 ซึ่งหมายความว่าโมดูลใดก็ตามที่อ้างอิงโดยใช้ ฟิลด์ "exports" เขียนด้วย JavaScript สมัยใหม่ได้ ผู้บริโภคที่ใช้แพ็กเกจต้อง จะถือว่าโมดูลที่มีช่อง "exports" มีโค้ดสมัยใหม่และเปลี่ยนรูปแบบหาก ตามความจำเป็น

ทันสมัยเท่านั้น

หากคุณต้องการเผยแพร่แพ็กเกจด้วยโค้ดสมัยใหม่และปล่อยให้เป็น ที่จะจัดการกับการเปลี่ยนรูปแบบเมื่อใช้เซิร์ฟเวอร์เป็นทรัพยากร Dependency ให้ใช้เฉพาะ "exports"

{
  "name": "foo",
  "exports": "./modern.js"
}

ทันสมัยพร้อมรายการสำรองแบบเดิม

ใช้ช่อง "exports" ร่วมกับ "main" เพื่อเผยแพร่แพ็กเกจ โดยใช้โค้ดสมัยใหม่ และยังมี ES5 + CommonJS สำรอง สำหรับรุ่นเดิม เบราว์เซอร์

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs"
}

ความทันสมัยด้วยทางเลือกเดิมและการเพิ่มประสิทธิภาพ Bundler ด้าน ESM

นอกจากการกำหนดจุดแรกเข้า CommonJS สำรองแล้ว ฟิลด์ "module" ยังสามารถ เพื่อชี้ไปยังแพ็กเกจวิดีโอสำรองแบบเดิมที่คล้ายกัน แต่เป็นชุดที่ใช้ ไวยากรณ์โมดูล JavaScript (import และ export)

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs",
  "module": "./module.js"
}

Bundler จำนวนมาก เช่น Webpack และ Rollup อาศัยช่องนี้เพื่อใช้ประโยชน์ ฟีเจอร์โมดูลและเปิดใช้ การสั่นสะเทือนของต้นไม้ นี่ยังคงเป็นแพ็กเกจเดิมที่ไม่มีโค้ดสมัยใหม่นอกเหนือจาก import/export ดังนั้นให้ใช้แนวทางนี้เพื่อจัดส่งโค้ดสมัยใหม่ที่มี วิดีโอสำรองรุ่นเดิมที่ยังคงได้รับการเพิ่มประสิทธิภาพสำหรับการรวมกลุ่ม

JavaScript สมัยใหม่ในแอปพลิเคชัน

ทรัพยากร Dependency ของบุคคลที่สามเป็นการใช้งานจริงส่วนใหญ่ของเวอร์ชันที่ใช้งานจริง โค้ด JavaScript ในเว็บแอปพลิเคชัน แม้ว่าที่ผ่านมาทรัพยากร Dependency ของ npm จะ ได้รับการเผยแพร่เป็นไวยากรณ์ ES5 แบบเดิมแล้ว นี่ไม่ใช่สมมติฐานที่ปลอดภัยอีกต่อไปและ ความเสี่ยง การอัปเดตการพึ่งพิงทำให้การสนับสนุนเบราว์เซอร์ในแอปพลิเคชันของคุณเสียหาย

ด้วยจำนวนแพ็กเกจ npm ที่เปลี่ยนมาใช้ JavaScript สมัยใหม่ คือตรวจสอบว่าได้ตั้งค่าเครื่องมือสร้าง ไว้เพื่อจัดการ มี มีโอกาสมาก แพ็กเกจ npm บางรายการที่คุณใช้อยู่แล้ว ฟีเจอร์ภาษาต่างๆ มีตัวเลือกมากมายสำหรับใช้รหัสสมัยใหม่ จาก npm โดยไม่ทำให้แอปพลิเคชันของคุณเสียหาย ในเบราว์เซอร์รุ่นเก่า แต่ แนวคิดคือให้ระบบบิลด์เปลี่ยนทรัพยากร Dependency เป็นไวยากรณ์เดียวกัน เป้าหมายเป็นซอร์สโค้ดของคุณ

Webpack

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

module.exports = {
  target: ['web', 'es2017'],
};

นอกจากนี้ ยังกำหนดค่า Webpack เพื่อสร้าง Bundle ที่เพิ่มประสิทธิภาพซึ่ง ละเว้นฟังก์ชัน Wrapper ที่ไม่จำเป็นเมื่อกำหนดเป้าหมายโมดูล ES สมัยใหม่ ของคุณ การดำเนินการนี้ยังกำหนดค่า Webpack ให้โหลดแพ็กเกจที่แยกโค้ดโดยใช้ <script type="module">

module.exports = {
  target: ['web', 'es2017'],
  output: {
    module: true,
  },
  experiments: {
    outputModule: true,
  },
};

มีปลั๊กอิน Webpack จำนวนมากที่ช่วยให้สามารถ คอมไพล์และส่ง JavaScript ที่ทันสมัย ขณะที่ยังคงสนับสนุนเบราว์เซอร์รุ่นเก่า เช่น ปลั๊กอิน Optimize และ BabelEsmPlugin

ปลั๊กอิน Optimize

ปลั๊กอิน Optimize เป็นเว็บแพ็ก ปลั๊กอินที่เปลี่ยนรูปแบบโค้ดชุดสุดท้ายจาก JavaScript สมัยใหม่เป็นแบบเดิม แทนที่จะเป็นไฟล์ต้นฉบับแต่ละไฟล์ เครื่องมือนี้เป็นการตั้งค่าในตัวที่ช่วยให้ การกำหนดค่า Webpack เพื่อให้ทุกอย่างเป็น JavaScript ที่ทันสมัยโดยไม่มี การแตกกิ่งแบบพิเศษสำหรับเอาต์พุตหรือไวยากรณ์หลายรายการ

เนื่องจากปลั๊กอิน Optimize ทำงานในรูปแบบชุดแทนที่จะเป็นโมดูลแต่ละโมดูล จะประมวลผลโค้ดของแอปพลิเคชันและทรัพยากร Dependency ได้เท่ากัน จึงทำให้ สามารถใช้ทรัพยากร Dependency ของ JavaScript สมัยใหม่จาก npm ได้ เนื่องจากโค้ดจะถูก กลุ่มและแปลงเป็นไวยากรณ์ที่ถูกต้อง และยังเร็วกว่า วิธีแก้ปัญหาแบบดั้งเดิมที่มี 2 ขั้นตอนในการรวบรวม ในขณะที่ยังคงสร้าง สำหรับเบราว์เซอร์สมัยใหม่และเบราว์เซอร์รุ่นเก่าแยกกัน แพ็กเกจทั้ง 2 ชุด ได้แก่ ออกแบบมาเพื่อให้โหลดโดยใช้ รูปแบบโมดูล/ไม่มีโมดูล

// webpack.config.js
const OptimizePlugin = require('optimize-plugin');

module.exports = {
  // ...
  plugins: [new OptimizePlugin()],
};

Optimize Plugin รวดเร็วและมีประสิทธิภาพมากกว่า Webpack ที่กำหนดเอง ซึ่งโดยทั่วไปจะรวมโค้ดสมัยใหม่กับโค้ดเดิมแยกกัน ทั้งนี้ ยังจัดการการเรียกใช้ Babel ให้กับคุณ และลดขนาด แพ็กเกจที่ใช้ Terser ซึ่งมีการตั้งค่าที่เหมาะสมแยกกันสำหรับ ทั้งสมัยใหม่และแบบเดิม สุดท้าย โพลีฟิลล์ที่เครื่องมือสร้าง ระบบจะแยก Bundle เดิมออกมาเป็นสคริปต์เฉพาะ เพื่อไม่ให้มี ซ้ำซ้อนหรือโหลดโดยไม่จำเป็นในเบราว์เซอร์รุ่นใหม่

การเปรียบเทียบ: การเปลี่ยนรูปแบบโมดูลแหล่งที่มา 2 ครั้งเทียบกับการรวมแพ็กเกจที่สร้างขึ้น

BabelEsmPlugin

BabelEsmPlugin เป็นเว็บแพ็ก ปลั๊กอินที่ทำงานร่วมกับ @babel/preset-env สร้าง Bundle ที่มีอยู่เป็นเวอร์ชันที่ทันสมัย เพื่อให้จัดส่งโค้ดที่มีการเปลี่ยนแปลงน้อยกว่า เบราว์เซอร์ที่ทันสมัย นี่เป็นโซลูชันที่ได้รับความนิยมมากที่สุดสำหรับ โมดูล/nomodule ใช้โดย Next.js และ Preact CLI

// webpack.config.js
const BabelEsmPlugin = require('babel-esm-plugin');

module.exports = {
  //...
  module: {
    rules: [
      // your existing babel-loader configuration:
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
  plugins: [new BabelEsmPlugin()],
};

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

กำหนดค่า Babel-loader เพื่อแปลง Node_modules

หากคุณใช้ babel-loader โดยไม่มีปลั๊กอินใดปลั๊กอินหนึ่งจาก 2 รายการก่อนหน้านี้ จะมีขั้นตอนสำคัญที่จำเป็นในการใช้ NPM ของ JavaScript ที่ทันสมัย โมดูล การกำหนดการกําหนดค่า babel-loader ที่แยกกัน 2 รายการช่วยให้เป็นไปได้ เพื่อรวบรวมฟีเจอร์ภาษาสมัยใหม่ที่พบใน node_modules โดยอัตโนมัติ ES2017 ขณะที่ยังคงเปลี่ยนรูปแบบโค้ดของบุคคลที่หนึ่งของคุณเองด้วย Babel ปลั๊กอินและค่าที่กำหนดล่วงหน้าที่กำหนดไว้ในการกำหนดค่าของโปรเจ็กต์ การดำเนินการนี้จะไม่ สร้างแพ็กเกจที่ทันสมัยและแบบเดิมสำหรับการตั้งค่าโมดูล/ไม่มีโมดูล แต่กลับมี ทำให้สามารถติดตั้งและใช้แพ็กเกจ npm ที่มี JavaScript ที่ทันสมัย โดยไม่ทำให้เบราว์เซอร์รุ่นเก่าเสียหาย

webpack-plugin-modern-npm ใช้เทคนิคนี้เพื่อรวบรวมทรัพยากร Dependency ของ npm ที่มีฟิลด์ "exports" ใน package.json ของตน เนื่องจากอาจมีไวยากรณ์สมัยใหม่:

// webpack.config.js
const ModernNpmPlugin = require('webpack-plugin-modern-npm');

module.exports = {
  plugins: [
    // auto-transpile modern stuff found in node_modules
    new ModernNpmPlugin(),
  ],
};

หรือจะใช้เทคนิคด้วยตนเองใน Webpack ก็ได้ โดยตรวจหาช่อง "exports" ใน package.json ของ เมื่อแก้ไขเรียบร้อยแล้ว การไม่ใส่แคชเพื่อความกระชับ การใช้งานอาจมีลักษณะเช่นนี้

// webpack.config.js
module.exports = {
  module: {
    rules: [
      // Transpile for your own first-party code:
      {
        test: /\.js$/i,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      // Transpile modern dependencies:
      {
        test: /\.js$/i,
        include(file) {
          let dir = file.match(/^.*[/\\]node_modules[/\\](@.*?[/\\])?.*?[/\\]/);
          try {
            return dir && !!require(dir[0] + 'package.json').exports;
          } catch (e) {}
        },
        use: {
          loader: 'babel-loader',
          options: {
            babelrc: false,
            configFile: false,
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};

เมื่อใช้วิธีการนี้ คุณต้องตรวจสอบว่าไวยากรณ์สมัยใหม่ได้รับการสนับสนุนโดย เครื่องมือลดขนาดของคุณ ทั้ง Terser และ uglify-es มีตัวเลือกในการระบุ {ecma: 2017} เพื่อเก็บรักษา และในบางกรณี สร้างไวยากรณ์ ES2017 ระหว่างการบีบอัดและการจัดรูปแบบ

ภาพรวม

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

@rollup/plugin-babel

หากคุณใช้ "ภาพรวม" ฟิลด์ getBabelOutputPlugin() วิธี (โดย ปลั๊กอิน Babel อย่างเป็นทางการ) แปลงโค้ดในแพ็กเกจที่สร้างขึ้นแทนที่จะเป็นโมดูลแหล่งที่มาแต่ละรายการ ภาพรวมมีการสนับสนุนในตัวสำหรับการสร้างแพ็กเกจหลายชุดเป็นส่วนหนึ่งของ เพียงบิลด์เดียว และแต่ละงานมีปลั๊กอินของตนเอง คุณใช้เครื่องมือนี้เพื่อสร้าง แพ็กเกจต่างๆ ทั้งสมัยใหม่และแบบเดิมโดยส่งแต่ละแพ็กเกจ การกำหนดค่าปลั๊กอินเอาต์พุต Babel:

// rollup.config.js
import {getBabelOutputPlugin} from '@rollup/plugin-babel';

export default {
  input: 'src/index.js',
  output: [
    // modern bundles:
    {
      format: 'es',
      plugins: [
        getBabelOutputPlugin({
          presets: [
            [
              '@babel/preset-env',
              {
                targets: {esmodules: true},
                bugfixes: true,
                loose: true,
              },
            ],
          ],
        }),
      ],
    },
    // legacy (ES5) bundles:
    {
      format: 'amd',
      entryFileNames: '[name].legacy.js',
      chunkFileNames: '[name]-[hash].legacy.js',
      plugins: [
        getBabelOutputPlugin({
          presets: ['@babel/preset-env'],
        }),
      ],
    },
  ],
};

เครื่องมือสร้างเพิ่มเติม

ภาพรวมและเว็บแพ็กสามารถกำหนดค่าได้สูง ซึ่งโดยทั่วไปหมายความว่าแต่ละโปรเจ็กต์ ต้องอัปเดตการกำหนดค่าเพื่อเปิดใช้ไวยากรณ์ JavaScript สมัยใหม่ในทรัพยากร Dependency นอกจากนี้ยังมีเครื่องมือสร้างระดับสูงขึ้นที่ยึดตามแบบแผนและค่าเริ่มต้นมากกว่า เช่น Parcel, Snowpack, Vite และ WMR เครื่องมือเหล่านี้ส่วนใหญ่ จะถือว่าทรัพยากร Dependency ของ npm อาจมีไวยากรณ์แบบใหม่ และจะแปลงเป็น ระดับไวยากรณ์ที่เหมาะสมเมื่อสร้าง สำหรับเวอร์ชันที่ใช้งานจริง

นอกเหนือจากปลั๊กอินเฉพาะสำหรับ Webpack และ Rollup แล้ว JavaScript ที่ทันสมัย สามารถเพิ่มแพ็กเกจที่มีวิดีโอสำรองแบบเดิมลงในโปรเจ็กต์ใดก็ได้โดยใช้ devolution การปฏิวัติเป็น เครื่องมือแบบสแตนด์อโลนที่แปลงเอาต์พุตจากระบบบิลด์เพื่อสร้างผลงานเก่า ตัวแปร JavaScript ทำให้การรวมกลุ่มและการแปลงอยู่ในรูปแบบของ เป้าหมายเอาต์พุต