ใน Codelab นี้ ให้ปรับปรุงประสิทธิภาพของแอปพลิเคชันแบบง่ายนี้ที่ช่วยให้ผู้ใช้ให้คะแนนแมวแบบสุ่มได้ ดูวิธีเพิ่มประสิทธิภาพกลุ่ม JavaScript โดยลดจำนวนโค้ดที่เปลี่ยนรูปแบบ
ในแอปตัวอย่าง คุณเลือกคำหรืออีโมจิเพื่อสื่อความชอบแมวแต่ละตัวได้ เมื่อคลิกปุ่ม แอปจะแสดงค่าของปุ่มใต้รูปภาพแมวปัจจุบัน
วัดระยะทาง
เป็นความคิดที่ดีที่จะเริ่มต้นด้วยการตรวจสอบเว็บไซต์ก่อนที่จะเพิ่มการเพิ่มประสิทธิภาพใดๆ
- หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
- กด "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 แบบเก่า เนื่องจากการเปลี่ยนแปลงเหล่านี้เป็นการเปลี่ยนแปลงที่เกี่ยวข้องกับไวยากรณ์ (เช่น ฟังก์ชันลูกศร) จึงไม่สามารถจำลองด้วย Polyfills
ดูที่ 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
จะผสานรวมกับรายการเบราว์เซอร์ ซึ่งหมายความว่าคุณจะดูรายการค้นหาทั้งหมดที่เข้ากันได้ซึ่งใช้ในช่องนี้ได้ในเอกสารประกอบเกี่ยวกับรายการเบราว์เซอร์
ค่า "last 2 versions"
จะเปลี่ยนรูปแบบโค้ดในแอปพลิเคชันสำหรับ 2 เวอร์ชันล่าสุดของทุกเบราว์เซอร์
การแก้ไขข้อบกพร่อง
หากต้องการดูเป้าหมาย Babel ทั้งหมดของเบราว์เซอร์ รวมถึงการเปลี่ยนรูปแบบและ Polyfill ทั้งหมดที่เพิ่มเข้ามา ให้เพิ่มช่อง debug
ลงใน .babelrc:
{
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 versions",
"debug": true
}
]
]
}
- คลิกเครื่องมือ
- คลิกบันทึก
โหลดแอปพลิเคชันซ้ำและดูบันทึกสถานะ Glitch ที่ด้านล่างของเครื่องมือแก้ไข
เบราว์เซอร์เป้าหมาย
Babel จะบันทึกรายละเอียดจำนวนหนึ่งเกี่ยวกับกระบวนการคอมไพล์ ซึ่งรวมถึงสภาพแวดล้อมเป้าหมายทั้งหมดที่มีการรวบรวมโค้ดไว้ไปยังคอนโซล
สังเกตว่าเบราว์เซอร์ที่ปิดให้บริการแล้ว เช่น Internet Explorer จะรวมอยู่ในรายการนี้อย่างไร ปัญหานี้เกิดจากเบราว์เซอร์ที่ไม่รองรับจะไม่มีการเพิ่ม ฟีเจอร์ใหม่ๆ และ Babel จะยังคงแปลงไวยากรณ์ที่เฉพาะเจาะจงสำหรับเบราว์เซอร์ดังกล่าว ซึ่งจะเพิ่มขนาดของชุดไฟล์โดยไม่จำเป็นหากผู้ใช้ไม่ได้ใช้เบราว์เซอร์นี้เพื่อเข้าถึงเว็บไซต์ของคุณ
นอกจากนี้ Babel ยังบันทึกรายการปลั๊กอิน Transform ที่ใช้:
มีรายการจำนวนมากแน่ๆ ปลั๊กอินทั้งหมดที่ Babel ต้องใช้ในการแปลงไวยากรณ์ ES2015+ เป็นไวยากรณ์ที่เก่ากว่าสำหรับเบราว์เซอร์เป้าหมายทั้งหมด
อย่างไรก็ตาม Babel จะไม่แสดงโพลีฟิลที่เฉพาะเจาะจงที่ใช้
เนื่องจากมีการนำเข้า @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"
}
]
]
}
โพลีฟิลล์จะรวมอยู่ด้วยโดยอัตโนมัติเมื่อจำเป็น
ซึ่งหมายความว่าคุณสามารถนำการนำเข้า @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",
}
]
]
}
ดูรายละเอียดของ Bundle ที่ดึงข้อมูล
เนื่องจากแอปพลิเคชันมีขนาดเล็กมาก การเปลี่ยนแปลงเหล่านี้จึงไม่มีความแตกต่างกันมากนัก อย่างไรก็ตาม ขอแนะนำให้ใช้เปอร์เซ็นต์ส่วนแบ่งการตลาดของเบราว์เซอร์ (เช่น ">0.25%"
) ควบคู่กับการยกเว้นเบราว์เซอร์บางรายการที่คุณมั่นใจว่าผู้ใช้ไม่ได้ใช้งาน อ่านบทความ "2 เวอร์ชันล่าสุด" ที่ถือเป็นอันตราย
โดย James Kyle เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้
ใช้ <script type="module">
เรายังมีสิ่งที่ต้องปรับปรุงอีกมาก แม้ว่าจะมีการนำโพลีฟิลล์ที่ไม่ได้ใช้งานออกจำนวนหนึ่งไปแล้ว แต่โพลีฟิลมีหลายรายการที่ถูกจัดส่งซึ่งไม่จำเป็นสำหรับบางเบราว์เซอร์ เมื่อใช้โมดูล ระบบสามารถเขียนและจัดส่งไวยากรณ์ที่ใหม่กว่าไปยังเบราว์เซอร์ได้โดยตรงโดยไม่ต้องใช้ 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 เวอร์ชันไปยังเบราว์เซอร์ได้ ดังนี้
- เวอร์ชันที่สามารถทำงานได้ในเบราว์เซอร์รุ่นใหม่ที่รองรับโมดูล และมีโมดูลที่ถอดข้อความไม่ได้เป็นส่วนใหญ่ แต่มีขนาดไฟล์ที่เล็กกว่า
- เวอร์ชันที่มีสคริปต์ที่มีขนาดใหญ่ขึ้นและเปลี่ยนรูปแบบแล้ว ซึ่งจะทำงานได้ในเบราว์เซอร์เดิมทุกชนิด
การใช้โมดูล 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
}
โปรดสังเกตว่าแทนที่จะใช้ค่า targets
สำหรับ "@babel/preset-env"
มีการใช้ esmodules
ที่มีค่าเป็น false
แทน ซึ่งหมายความว่า 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 เวอร์ชันล่าสุด
ระบบจะดึงข้อมูลเฉพาะโมดูลที่มีขนาดแพ็กเกจเล็กกว่ามากเพราะระบบไม่ได้แปลงข้อมูลเป็นปริมาณมาก เบราว์เซอร์จะไม่สนใจองค์ประกอบสคริปต์อื่นๆ โดยสิ้นเชิง
หากคุณโหลดแอปพลิเคชันในเบราว์เซอร์รุ่นเก่า ระบบจะดึงเฉพาะสคริปต์ที่มีการแปลงโฉมและมีขนาดใหญ่กว่าที่มีโพลีฟิลล์และการเปลี่ยนรูปแบบที่จำเป็นทั้งหมดเท่านั้น ต่อไปนี้เป็นภาพหน้าจอของคำขอทั้งหมดที่สร้างขึ้นใน Chrome เวอร์ชันเก่า (เวอร์ชัน 38)
บทสรุป
ตอนนี้คุณก็เข้าใจวิธีใช้ @babel/preset-env
เพื่อจัดหาเฉพาะ Polyfill ที่จำเป็นสำหรับเบราว์เซอร์เป้าหมายแล้ว และทราบวิธีที่โมดูล JavaScript ช่วยปรับปรุงประสิทธิภาพให้ดียิ่งขึ้นด้วยการจัดส่งแอปพลิเคชัน 2 เวอร์ชันที่แตกต่างกัน ความเข้าใจอย่างถ่องแท้ว่าเทคนิคทั้ง 2 อย่างนี้ช่วยลดขนาด
แพ็กเกจของคุณลงได้มากได้อย่างไร ก็ลงมือและเพิ่มประสิทธิภาพได้เลย