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

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

แอปพลิเคชันนี้ใช้พื้นที่มากกว่า 80 KB ถึงเวลาตรวจสอบว่ามีส่วนใดของแพ็กเกจที่ไม่ได้ใช้งานหรือไม่
กด
Control+Shift+P(หรือCommand+Shift+Pใน Mac) เพื่อเปิดเมนู Command
ป้อน
Show Coverageแล้วกดEnterเพื่อแสดงแท็บความครอบคลุมในแท็บการครอบคลุม ให้คลิกโหลดซ้ำเพื่อโหลดแอปพลิเคชันซ้ำขณะจับภาพการครอบคลุม

ดูปริมาณโค้ดที่ใช้เทียบกับปริมาณโค้ดที่โหลดสำหรับแพ็กเกจหลัก
กว่าครึ่งหนึ่งของแพ็กเกจ (44 KB) ไม่ได้ถูกนำมาใช้ด้วยซ้ำ เนื่องจากโค้ดจำนวนมากภายในประกอบด้วย Polyfill เพื่อให้แอปพลิเคชันทำงานในเบราว์เซอร์รุ่นเก่าได้
ใช้ @babel/preset-env
ไวยากรณ์ของภาษา JavaScript เป็นไปตามมาตรฐานที่เรียกว่า ECMAScript หรือ ECMA-262 ข้อกำหนดเวอร์ชันใหม่จะเผยแพร่ทุกปีและมีฟีเจอร์ใหม่ที่ผ่านกระบวนการข้อเสนอแล้ว เบราว์เซอร์หลักแต่ละรายการจะอยู่ในขั้นตอนที่แตกต่างกันเสมอในการรองรับฟีเจอร์เหล่านี้
ฟีเจอร์ ES2015 ต่อไปนี้ใช้ในแอปพลิเคชัน
นอกจากนี้ยังมีการใช้ฟีเจอร์ ES2017 ต่อไปนี้ด้วย
คุณสามารถเจาะลึกซอร์สโค้ดใน src/index.js เพื่อดูวิธีใช้ทั้งหมดนี้ได้
ฟีเจอร์ทั้งหมดนี้รองรับใน Chrome เวอร์ชันล่าสุด แต่เบราว์เซอร์อื่นๆ ที่ไม่รองรับฟีเจอร์เหล่านี้ล่ะ Babel ซึ่งรวมอยู่ในแอปพลิเคชันเป็นไลบรารีที่ได้รับความนิยมมากที่สุดที่ใช้ในการคอมไพล์โค้ดที่มีไวยากรณ์ใหม่กว่าให้เป็นโค้ดที่เบราว์เซอร์และสภาพแวดล้อมที่เก่ากว่าเข้าใจได้ โดยทำได้ 2 วิธีดังนี้
- Polyfill รวมอยู่ด้วยเพื่อจำลองฟังก์ชัน ES2015+ ที่ใหม่กว่า เพื่อให้สามารถใช้ API ได้แม้ว่าเบราว์เซอร์จะไม่รองรับก็ตาม ต่อไปนี้คือตัวอย่างของ Polyfill ของเมธอด
Array.includes - ปลั๊กอินใช้เพื่อเปลี่ยนรูปแบบโค้ด ES2015 (หรือใหม่กว่า) เป็นไวยากรณ์ ES5 ที่เก่ากว่า เนื่องจากการเปลี่ยนแปลงเหล่านี้เกี่ยวข้องกับไวยากรณ์ (เช่น ฟังก์ชันลูกศร) จึงไม่สามารถจำลองด้วย Polyfill ได้
ดู package.json เพื่อดูว่ามีไลบรารี Babel ใดบ้างที่รวมอยู่ด้วย
"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 ไว้ในแอปพลิเคชันหากคุณใช้ Bundler โมดูลอื่นที่ไม่ใช่ Webpack
แอตทริบิวต์ targets ใน .babelrc จะระบุเบราว์เซอร์ที่กำหนดเป้าหมาย @babel/preset-env
ผสานรวมกับ browserslist ซึ่งหมายความว่าคุณจะดูรายการคำค้นหาที่เข้ากันได้ทั้งหมดซึ่งใช้ในช่องนี้ได้ในเอกสารประกอบของ browserlist
ค่า "last 2 versions" จะทำการ Transpile โค้ดในแอปพลิเคชันสำหรับเบราว์เซอร์ทุกเวอร์ชัน 2 เวอร์ชันล่าสุด
การแก้ไขข้อบกพร่อง
หากต้องการดูเป้าหมาย Babel ทั้งหมดของเบราว์เซอร์ รวมถึงการเปลี่ยนรูปแบบและ Polyfill ทั้งหมดที่รวมอยู่ ให้เพิ่มช่อง debug ลงใน .babelrc:
{
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 versions",
"debug": true
}
]
]
}
- คลิกเครื่องมือ
- คลิกบันทึก
โหลดแอปพลิเคชันซ้ำและดูบันทึกสถานะของ Glitch ที่ด้านล่างของเครื่องมือแก้ไข
เบราว์เซอร์ที่กำหนดเป้าหมาย
Babel จะบันทึกรายละเอียดจำนวนมากเกี่ยวกับกระบวนการคอมไพล์ลงในคอนโซล ซึ่งรวมถึงสภาพแวดล้อมเป้าหมายทั้งหมดที่โค้ดได้รับการคอมไพล์

โปรดทราบว่าเบราว์เซอร์ที่เลิกใช้งานแล้ว เช่น Internet Explorer จะรวมอยู่ในรายการนี้ด้วย ซึ่งเป็นปัญหาเนื่องจากเบราว์เซอร์ที่ไม่รองรับจะไม่มีฟีเจอร์ใหม่ๆ เพิ่มเข้ามา และ Babel จะยังคงทำการ Transpile ไวยากรณ์เฉพาะสำหรับเบราว์เซอร์เหล่านั้นต่อไป ซึ่งจะเพิ่มขนาดของแพ็กเกจโดยไม่จำเป็นหากผู้ใช้ไม่ได้ใช้เบราว์เซอร์นี้เพื่อเข้าถึงเว็บไซต์ของคุณ
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>
ฟีเจอร์ ECMAScript ใหม่ๆ จำนวนมากได้รับการรองรับแล้วในสภาพแวดล้อมที่รองรับโมดูล JavaScript (แทนที่จะต้องใช้ Babel) ซึ่งหมายความว่าคุณสามารถแก้ไขการกำหนดค่า Babel เพื่อส่งแอปพลิเคชัน 2 เวอร์ชันที่แตกต่างกันไปยังเบราว์เซอร์ได้ ดังนี้
- เวอร์ชันที่จะทำงานในเบราว์เซอร์ที่ใหม่กว่าซึ่งรองรับโมดูล และมีโมดูลที่ส่วนใหญ่ไม่ได้ผ่านการแปลง แต่มีขนาดไฟล์ที่เล็กกว่า
- เวอร์ชันที่มีสคริปต์ที่ผ่านการ Transpile ขนาดใหญ่ขึ้นซึ่งจะทำงานในเบราว์เซอร์เดิมได้
การใช้โมดูล 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
}
โปรดทราบว่าระบบจะใช้ esmodules ที่มีค่าเป็น false แทนการใช้ค่า targets สำหรับ "@babel/preset-env" ซึ่งหมายความว่า 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
];
ตอนนี้ระบบจะสร้างทั้งโมดูลขนาดเล็กลงสำหรับเบราว์เซอร์ที่รองรับและสคริปต์ที่ทำการ Transpile ขนาดใหญ่ขึ้นสำหรับเบราว์เซอร์รุ่นเก่า
เบราว์เซอร์ที่รองรับโมดูลจะละเว้นสคริปต์ที่มีแอตทริบิวต์ 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 ยังไม่รองรับเอาต์พุตของทั้งสคริปต์โมดูลและสคริปต์ที่ไม่ใช่โมดูล แม้ว่าจะมีวิธีแก้ปัญหาชั่วคราวและปลั๊กอินแยกต่างหากที่สร้างขึ้นเพื่อแก้ปัญหานี้ เช่น BabelMultiTargetPlugin และ HTMLWebpackMultiBuildPlugin แต่บทแนะนำนี้จะใช้วิธีที่ง่ายกว่าในการเพิ่มองค์ประกอบสคริปต์โมดูลด้วยตนเอง
เพิ่มโค้ดต่อไปนี้ใน src/index.js ที่ส่วนท้ายของไฟล์
...
</form>
<script type="module" src="main.mjs"></script>
</body>
</html>
ตอนนี้ให้โหลดแอปพลิเคชันในเบราว์เซอร์ที่รองรับโมดูล เช่น Chrome เวอร์ชันล่าสุด

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

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