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

ในแอปตัวอย่าง คุณสามารถเลือกคำหรืออีโมจิเพื่อสื่อว่าชอบแมวแต่ละตัวมากน้อยเพียงใด เมื่อคลิกปุ่ม แอปจะแสดงค่าของปุ่มใต้รูปภาพแมวปัจจุบัน
วัดผล
คุณควรเริ่มด้วยการตรวจสอบเว็บไซต์ก่อนที่จะเพิ่มการเพิ่มประสิทธิภาพใดๆ เสมอ โดยทำดังนี้
- หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกด
เต็มหน้าจอ
- กด `Control+Shift+J` (หรือ `Command+Option+J` ใน Mac) เพื่อเปิด DevTools
- คลิกแท็บเครือข่าย
- เลือกช่องทำเครื่องหมายปิดใช้แคช
- โหลดแอปซ้ำ

แอปพลิเคชันนี้ใช้พื้นที่มากกว่า 80 KB วิธีตรวจสอบว่าไม่ได้ใช้ส่วนใดส่วนหนึ่งของแพ็กเกจ
- กด - Control+Shift+P(หรือ- Command+Shift+Pใน Mac) เพื่อเปิดเมนูคำสั่ง 
- ป้อน - Show Coverageแล้วกด- Enterเพื่อแสดงแท็บความครอบคลุม
- ในแท็บการครอบคลุม ให้คลิกโหลดซ้ำเพื่อโหลดแอปพลิเคชันซ้ำขณะจับภาพการครอบคลุม  
- ดูว่ามีการใช้โค้ดมากเพียงใดเทียบกับโค้ดที่โหลดสำหรับ แพ็กเกจหลัก   
และไม่ได้ใช้ประโยชน์จากกว่าครึ่งของแพ็กเกจ (44 KB) เนื่องจากโค้ดจำนวนมากภายในประกอบด้วย Polyfill เพื่อให้แน่ใจว่าแอปพลิเคชันจะทำงานในเบราว์เซอร์รุ่นเก่าได้
ใช้ @babel/preset-env
ไวยากรณ์ของภาษา JavaScript เป็นไปตามมาตรฐานที่เรียกว่า ECMAScript หรือ ECMA-262 เราจะเผยแพร่ข้อกำหนดเวอร์ชันใหม่ทุกปีและมีฟีเจอร์ใหม่ๆ ที่ผ่านกระบวนการเสนอ เบราว์เซอร์หลักแต่ละรายการจะรองรับฟีเจอร์เหล่านี้ในระยะต่างๆ เสมอ
แอปพลิเคชันใช้ฟีเจอร์ ES2015 ต่อไปนี้
นอกจากนี้ยังใช้ฟีเจอร์ ES2017 ต่อไปนี้ด้วย
คุณสามารถดูซอร์สโค้ดใน src/index.js เพื่อดูวิธีใช้ฟีเจอร์ทั้งหมดนี้
ได้
Chrome เวอร์ชันล่าสุดรองรับฟีเจอร์ทั้งหมดนี้ แต่เบราว์เซอร์อื่นๆ ที่ไม่รองรับฟีเจอร์เหล่านี้ล่ะ Babel ซึ่งรวมอยู่ในแอปพลิเคชันเป็นไลบรารีที่ได้รับความนิยมมากที่สุดที่ใช้ในการคอมไพล์ โค้ดที่มีไวยากรณ์ใหม่กว่าให้เป็นโค้ดที่เบราว์เซอร์และสภาพแวดล้อมรุ่นเก่ากว่า เข้าใจได้ โดยทำได้ 2 วิธีดังนี้
- ระบบจะรวม Polyfill เพื่อจำลองฟังก์ชัน ES2015+ เวอร์ชันใหม่กว่าเพื่อให้ใช้ API ได้แม้ว่าเบราว์เซอร์จะไม่รองรับก็ตาม
 ต่อไปนี้คือตัวอย่างพอลีฟิลของเมธอด Array.includes
- ปลั๊กอินใช้เพื่อเปลี่ยนโค้ด ES2015 (หรือใหม่กว่า) เป็นไวยากรณ์ ES5 รุ่นเก่า เนื่องจากการเปลี่ยนแปลงเหล่านี้เกี่ยวข้องกับไวยากรณ์ (เช่น ฟังก์ชันลูกศร) จึงไม่สามารถจำลองด้วย Polyfill ได้
ดูว่ามีไลบรารี Babel ใดบ้างที่รวมอยู่ได้ที่ package.json
"dependencies": {
  "@babel/polyfill": "^7.0.0"
},
"devDependencies": {
  //...
  "babel-loader": "^8.0.2",
  "@babel/core": "^7.1.0",
  "@babel/preset-env": "^7.1.0",
  //...
}
- @babel/coreคือคอมไพเลอร์ Babel หลัก ด้วยวิธีนี้ การกำหนดค่า Babel ทั้งหมดจะกำหนดไว้ใน- .babelrcที่รูทของโปรเจ็กต์
- babel-loaderรวม Babel ไว้ในกระบวนการบิลด์ webpack
ตอนนี้ให้ดูที่ webpack.config.js เพื่อดูว่ามีการรวม babel-loader เป็นกฎอย่างไร
module: {
  rules: [
    //...
    {
      test: /\.js$/,
      exclude: /node_modules/,
      loader: "babel-loader"
    }
  ]
},
- @babel/polyfillมี Polyfill ที่จำเป็นทั้งหมดสำหรับฟีเจอร์ ECMAScript ใหม่กว่า เพื่อให้ฟีเจอร์เหล่านั้นทำงานในสภาพแวดล้อมที่ไม่รองรับได้ มีการนำเข้าไว้ที่ด้านบนสุดของ- src/index.js.แล้ว
import "./style.css";
import "@babel/polyfill";
- @babel/preset-envระบุการแปลงและ Polyfill ที่จำเป็น สำหรับเบราว์เซอร์หรือสภาพแวดล้อมที่เลือกเป็นเป้าหมาย
ดูไฟล์การกำหนดค่า Babel, .babelrc เพื่อดูวิธีรวม
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "last 2 versions"
      }
    ]
  ]
}
นี่คือการตั้งค่า Babel และ webpack ดูวิธีรวม Babel ไว้ใน แอปพลิเคชันหากคุณใช้เครื่องมือจัดกลุ่มโมดูลอื่นที่ไม่ใช่ webpack
แอตทริบิวต์ targets
ใน .babelrc ระบุเบราว์เซอร์ที่เป็นเป้าหมาย @babel/preset-env
ผสานรวมกับ Browserslist ซึ่งหมายความว่าคุณจะดูรายการแบบสอบถามที่เข้ากันได้ทั้งหมด
ซึ่งใช้ในช่องนี้ได้ในเอกสารประกอบของ Browserslist
"last 2 versions" ค่าจะแปลงรหัสในแอปพลิเคชันสำหรับเบราว์เซอร์ทุกเบราว์เซอร์2 เวอร์ชันล่าสุด
การแก้ไขข้อบกพร่อง
หากต้องการดูเป้าหมาย Babel ของเบราว์เซอร์ทั้งหมด รวมถึงการแปลงและ Polyfill ทั้งหมดที่รวมอยู่ ให้เพิ่มฟิลด์ debug ลงใน .babelrc:
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "last 2 versions",
        "debug": true
      }
    ]
  ]
}
- คลิกเครื่องมือ
- คลิกบันทึก
โหลดแอปพลิเคชันซ้ำและดูบันทึกสถานะ Glitch ที่ด้านล่างของโปรแกรมแก้ไข
เบราว์เซอร์เป้าหมาย
Babel จะบันทึกรายละเอียดหลายอย่างลงในคอนโซลเกี่ยวกับกระบวนการคอมไพล์ รวมถึงสภาพแวดล้อมเป้าหมายทั้งหมดที่คอมไพล์โค้ด

โปรดสังเกตว่าเบราว์เซอร์ที่เลิกใช้งานแล้ว เช่น Internet Explorer จะรวมอยู่ใน รายการนี้ ซึ่งเป็นปัญหาเนื่องจากเบราว์เซอร์ที่ไม่รองรับจะไม่มีการเพิ่มฟีเจอร์ใหม่ๆ และ Babel จะยังคงแปลงไวยากรณ์ที่เฉพาะเจาะจงสำหรับเบราว์เซอร์เหล่านั้นต่อไป ซึ่งจะเพิ่มขนาดของแพ็กเกจโดยไม่จำเป็นหากผู้ใช้ไม่ได้ใช้เบราว์เซอร์นี้เพื่อเข้าถึงเว็บไซต์
นอกจากนี้ Babel ยังบันทึกรายการปลั๊กอินการแปลงที่ใช้ด้วย

รายการยาวมากเลยนะ ปลั๊กอินเหล่านี้ทั้งหมดเป็นปลั๊กอินที่ Babel ต้องใช้เพื่อแปลงไวยากรณ์ ES2015+ เป็นไวยากรณ์รุ่นเก่าสำหรับเบราว์เซอร์เป้าหมายทั้งหมด
อย่างไรก็ตาม Babel จะไม่แสดง Polyfill ที่เฉพาะเจาะจงที่ใช้

เนื่องจากระบบจะนำเข้า @babel/polyfill ทั้งหมดโดยตรง
โหลด Polyfill ทีละรายการ
โดยค่าเริ่มต้น Babel จะรวม Polyfill ทุกรายการที่จำเป็นสำหรับสภาพแวดล้อม ES2015+ ที่สมบูรณ์เมื่อมีการนำเข้า @babel/polyfill ไปยังไฟล์ หากต้องการนำเข้า Polyfill ที่เฉพาะเจาะจงซึ่งจำเป็นสำหรับ
เบราว์เซอร์เป้าหมาย ให้เพิ่ม useBuiltIns: 'entry' ลงในการกำหนดค่า
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "last 2 versions",
        "debug": true
        "useBuiltIns": "entry"
      }
    ]
  ]
}
โหลดแอปพลิเคชันซ้ำ ตอนนี้คุณจะเห็น Polyfill ทั้งหมดที่รวมไว้ได้แล้ว

แม้ว่าตอนนี้จะมีเฉพาะ Polyfill ที่จำเป็นสำหรับ "last 2 versions" แต่ก็ยังเป็นรายการที่ยาวมากอยู่ดี เนื่องจากยังคงมี
Polyfill ที่จำเป็นสำหรับเบราว์เซอร์เป้าหมายสำหรับฟีเจอร์ใหม่ทุกรายการ เปลี่ยนค่าของแอตทริบิวต์เป็น usage
เพื่อรวมเฉพาะแอตทริบิวต์ที่จำเป็นสำหรับฟีเจอร์ที่ใช้ในโค้ด
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "last 2 versions",
        "debug": true,
        "useBuiltIns": "entry"
        "useBuiltIns": "usage"
      }
    ]
  ]
}
ด้วยวิธีนี้ ระบบจะรวม Polyfill โดยอัตโนมัติเมื่อจำเป็น
ซึ่งหมายความว่าคุณสามารถนำเข้า @babel/polyfill ใน src/index.js. ออกได้
import "./style.css";
import "@babel/polyfill";
ตอนนี้จะรวมเฉพาะ Polyfill ที่จำเป็นสำหรับแอปพลิเคชันเท่านั้น

ขนาดแพ็กเกจแอปพลิเคชันลดลงอย่างมาก

การจำกัดรายการเบราว์เซอร์ที่รองรับ
จำนวนเป้าหมายเบราว์เซอร์ที่รวมไว้ยังคงมีจำนวนมาก และมีผู้ใช้จำนวนไม่มาก ที่ใช้เบราว์เซอร์ที่เลิกใช้งานแล้ว เช่น Internet Explorer อัปเดตการกำหนดค่า เป็นดังนี้
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "last 2 versions",
        "targets": [">0.25%", "not ie 11"],
        "debug": true,
        "useBuiltIns": "usage",
      }
    ]
  ]
}
ดูรายละเอียดของแพ็กเกจที่ดึงข้อมูลมา

เนื่องจากแอปพลิเคชันมีขนาดเล็กมาก การเปลี่ยนแปลงเหล่านี้จึงไม่ได้สร้างความแตกต่างมากนัก อย่างไรก็ตาม วิธีที่แนะนำคือการใช้เปอร์เซ็นต์ส่วนแบ่งการตลาดของเบราว์เซอร์ (เช่น
">0.25%") ควบคู่ไปกับการยกเว้นเบราว์เซอร์ที่เฉพาะเจาะจงซึ่งคุณมั่นใจว่าผู้ใช้ของคุณไม่ได้ใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในบทความ
"Last 2 versions" considered harmful
ของ James Kyle
ใช้ <script type="module">
เรายังคงปรับปรุงได้อีก แม้ว่าเราจะนำ Polyfill ที่ไม่ได้ใช้จำนวนหนึ่งออกไปแล้ว แต่ก็ยังมี Polyfill อีกหลายรายการที่จัดส่งมาด้วยซึ่งไม่จำเป็นสำหรับเบราว์เซอร์บางตัว การใช้โมดูลช่วยให้เขียนและจัดส่งไวยากรณ์ใหม่ๆ ไปยังเบราว์เซอร์ได้โดยตรงโดยไม่ต้องใช้ Polyfill ที่ไม่จำเป็น
โมดูล JavaScript เป็นฟีเจอร์ใหม่ที่รองรับในเบราว์เซอร์หลักทั้งหมด
คุณสร้างโมดูลได้โดยใช้แอตทริบิวต์ type="module" เพื่อกำหนดสคริปต์ที่นำเข้าและส่งออกจากโมดูลอื่นๆ เช่น
// math.mjs
export const add = (x, y) => x + y;
<!-- index.html -->
<script type="module">
  import { add } from './math.mjs';
  add(5, 2); // 7
</script>
สภาพแวดล้อมที่รองรับโมดูล JavaScript (โดยไม่ต้องใช้ Babel) รองรับฟีเจอร์ ECMAScript ใหม่ๆ หลายอย่างอยู่แล้ว ซึ่งหมายความว่าคุณสามารถแก้ไขการกำหนดค่า Babel เพื่อส่งแอปพลิเคชัน 2 เวอร์ชันที่แตกต่างกันไปยังเบราว์เซอร์ได้
- เวอร์ชันที่ใช้ได้ในเบราว์เซอร์รุ่นใหม่ที่รองรับโมดูล และมีโมดูลที่ไม่ได้แปลงเป็น JavaScript แต่มีขนาดไฟล์เล็กลง
- เวอร์ชันที่มีสคริปต์ที่ใหญ่ขึ้นและแปลงแล้วซึ่งจะทำงานในเบราว์เซอร์รุ่นเดิมได้
การใช้โมดูล ES กับ Babel
หากต้องการมี@babel/preset-envการตั้งค่าแยกกันสำหรับแอปพลิเคชัน 2 เวอร์ชัน
 ให้นำไฟล์ .babelrc ออก คุณเพิ่มการตั้งค่า Babel ลงในการกำหนดค่า webpack ได้โดยการระบุรูปแบบการคอมไพล์ที่แตกต่างกัน 2 รูปแบบสำหรับแอปพลิเคชันแต่ละเวอร์ชัน
เริ่มต้นด้วยการเพิ่มการกำหนดค่าสำหรับสคริปต์เดิมไปยัง webpack.config.js ดังนี้
const legacyConfig = {
  entry,
  output: {
    path: path.resolve(__dirname, "public"),
    filename: "[name].bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader",
        options: {
          presets: [
            ["@babel/preset-env", {
              useBuiltIns: "usage",
              targets: {
                esmodules: false
              }
            }]
          ]
        }
      },
      cssRule
    ]
  },
  plugins
}
โปรดทราบว่าระบบจะใช้ค่า false แทนค่า targets สำหรับ "@babel/preset-env"
esmodules ซึ่งหมายความว่า Babel
 จะรวมการแปลงและ Polyfill ที่จำเป็นทั้งหมดเพื่อกำหนดเป้าหมายเบราว์เซอร์ทุกเบราว์เซอร์ที่ยังไม่รองรับโมดูล ES
เพิ่มออบเจ็กต์ entry, cssRule และ corePlugins ที่จุดเริ่มต้นของไฟล์
webpack.config.js โดยจะแชร์ระหว่างโมดูลและสคริปต์เดิมที่แสดงในเบราว์เซอร์
const entry = {
  main: "./src"
};
const cssRule = {
  test: /\.css$/,
  use: ExtractTextPlugin.extract({
    fallback: "style-loader",
    use: "css-loader"
  })
};
const plugins = [
  new ExtractTextPlugin({filename: "[name].css", allChunks: true}),
  new HtmlWebpackPlugin({template: "./src/index.html"})
];
ตอนนี้ให้สร้างออบเจ็กต์การกำหนดค่าสำหรับสคริปต์โมดูลด้านล่างในลักษณะเดียวกันกับที่กำหนด legacyConfig
const moduleConfig = {
  entry,
  output: {
    path: path.resolve(__dirname, "public"),
    filename: "[name].mjs"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader",
        options: {
          presets: [
            ["@babel/preset-env", {
              useBuiltIns: "usage",
              targets: {
                esmodules: true
              }
            }]
          ]
        }
      },
      cssRule
    ]
  },
  plugins
}
ความแตกต่างหลักในที่นี้คือมีการใช้นามสกุลไฟล์ .mjs สำหรับชื่อไฟล์เอาต์พุต
 ค่า esmodules ตั้งค่าเป็นจริงที่นี่ ซึ่งหมายความว่าโค้ด
ที่เอาต์พุตไปยังโมดูลนี้เป็นสคริปต์ขนาดเล็กที่คอมไพล์น้อยกว่า
ซึ่งไม่ต้องผ่านการแปลงใดๆ ในตัวอย่างนี้ เนื่องจากฟีเจอร์ทั้งหมดที่ใช้
ได้รับการรองรับในเบราว์เซอร์ที่รองรับโมดูลอยู่แล้ว
ที่ท้ายสุดของไฟล์ ให้ส่งออกทั้ง 2 การกำหนดค่าในอาร์เรย์เดียว
module.exports = [
  legacyConfig, moduleConfig
];
ตอนนี้การดำเนินการนี้จะสร้างทั้งโมดูลขนาดเล็กสำหรับเบราว์เซอร์ที่รองรับและสคริปต์ที่แปลงแล้วขนาดใหญ่กว่าสำหรับเบราว์เซอร์รุ่นเก่า
เบราว์เซอร์ที่รองรับโมดูลจะข้ามสคริปต์ที่มีแอตทริบิวต์ nomodule
ในทางกลับกัน เบราว์เซอร์ที่ไม่รองรับโมดูลจะไม่สนใจองค์ประกอบสคริปต์ที่มีtype="module" ซึ่งหมายความว่าคุณสามารถรวมทั้งโมดูลและ
รายการสำรองที่คอมไพล์แล้ว โดยหลักแล้ว แอปพลิเคชันทั้ง 2 เวอร์ชันควรมีลักษณะดังนี้index.html
<script type="module" src="main.mjs"></script>
<script nomodule src="main.bundle.js"></script>
เบราว์เซอร์ที่รองรับโมดูลจะดึงข้อมูลและเรียกใช้ main.mjs และไม่สนใจ main.bundle.js. เบราว์เซอร์ที่ไม่รองรับโมดูลจะทําตรงกันข้าม
โปรดทราบว่าสคริปต์โมดูลจะเลื่อนการโหลดโดยค่าเริ่มต้นเสมอ ซึ่งแตกต่างจากสคริปต์ปกติ
หากต้องการให้สคริปต์ nomodule ที่เทียบเท่าเลื่อนการโหลดและเรียกใช้หลังจากแยกวิเคราะห์แล้วเท่านั้น คุณจะต้องเพิ่มแอตทริบิวต์ defer
<script type="module" src="main.mjs"></script>
<script nomodule src="main.bundle.js" defer></script>
สิ่งสุดท้ายที่ต้องทำที่นี่คือการเพิ่มแอตทริบิวต์ module และ nomodule
 ลงในโมดูลและสคริปต์เดิมตามลำดับ นำเข้า
ScriptExtHtmlWebpackPlugin
 ที่ด้านบนสุดของ webpack.config.js:
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ScriptExtHtmlWebpackPlugin = require("script-ext-html-webpack-plugin");
ตอนนี้ให้อัปเดตอาร์เรย์ plugins ในการกำหนดค่าเพื่อรวมปลั๊กอินนี้
const plugins = [
  new ExtractTextPlugin({filename: "[name].css", allChunks: true}),
  new HtmlWebpackPlugin({template: "./src/index.html"}),
  new ScriptExtHtmlWebpackPlugin({
    module: /\.mjs$/,
    custom: [
      {
        test: /\.js$/,
        attribute: 'nomodule',
        value: ''
    },
    ]
  })
];
การตั้งค่าปลั๊กอินเหล่านี้จะเพิ่มแอตทริบิวต์ type="module" สำหรับองค์ประกอบสคริปต์ .mjs ทั้งหมด รวมถึงแอตทริบิวต์ nomodule สำหรับโมดูลสคริปต์ .js ทั้งหมด
การแสดงโมดูลในเอกสาร HTML
สิ่งสุดท้ายที่ต้องทำคือการส่งออกทั้งองค์ประกอบสคริปต์เดิมและสคริปต์สมัยใหม่ไปยังไฟล์ HTML ขออภัย ปลั๊กอินที่สร้างไฟล์ HTML สุดท้าย HTMLWebpackPlugin ไม่รองรับเอาต์พุตของทั้งสคริปต์โมดูลและสคริปต์ nomodule ในขณะนี้ แม้ว่าจะมีวิธีแก้ปัญหาและปลั๊กอินแยกต่างหากที่สร้างขึ้นเพื่อแก้ปัญหานี้ เช่น BabelMultiTargetPlugin และ HTMLWebpackMultiBuildPlugin แต่ในบทแนะนำนี้จะใช้วิธีที่ง่ายกว่าในการเพิ่มองค์ประกอบสคริปต์โมดูลด้วยตนเอง
เพิ่มข้อมูลต่อไปนี้ลงใน src/index.js ที่ส่วนท้ายของไฟล์
    ...
    </form>
    <script type="module" src="main.mjs"></script>
  </body>
</html>
ตอนนี้ให้โหลดแอปพลิเคชันในเบราว์เซอร์ที่รองรับโมดูล เช่น Chrome เวอร์ชันล่าสุด

ระบบจะดึงข้อมูลเฉพาะโมดูล โดยมีขนาดแพ็กเกจน้อยกว่ามากเนื่องจากไม่ได้ แปลงโค้ดเป็น JavaScript ที่เข้ากันได้กับเบราว์เซอร์รุ่นเก่า เบราว์เซอร์จะเพิกเฉยต่อองค์ประกอบสคริปต์อื่นๆ ทั้งหมด
หากโหลดแอปพลิเคชันในเบราว์เซอร์รุ่นเก่า ระบบจะดึงเฉพาะสคริปต์ที่ใหญ่กว่าซึ่งได้รับการแปลง และมี Polyfill และการแปลงทั้งหมดที่จำเป็น นี่คือ ภาพหน้าจอของคำขอทั้งหมดที่สร้างขึ้นใน Chrome เวอร์ชันเก่า (เวอร์ชัน 38)

บทสรุป
ตอนนี้คุณก็เข้าใจวิธีใช้ @babel/preset-env เพื่อระบุเฉพาะ
Polyfill ที่จำเป็นสำหรับเบราว์เซอร์เป้าหมายแล้ว นอกจากนี้ คุณยังทราบวิธีที่โมดูล JavaScript
 สามารถปรับปรุงประสิทธิภาพให้ดียิ่งขึ้นได้ด้วยการจัดส่งแอปพลิเคชัน 2 เวอร์ชันที่แตกต่างกันซึ่งผ่านการแปลงรหัส เมื่อเข้าใจวิธีที่เทคนิคทั้ง 2 อย่างนี้ช่วยลดขนาดแพ็กเกจลงได้อย่างมากแล้ว ก็เริ่มเพิ่มประสิทธิภาพได้เลย
