Webpack ช่วยแคชเนื้อหาได้อย่างไร
ขั้นตอนถัดไป (หลังจากการเพิ่มประสิทธิภาพขนาดแอปที่ ปรับปรุงเวลาที่ใช้ในการโหลดแอปคือการแคช ใช้เพื่อทำให้ส่วนต่างๆ ของแอปอยู่บน และหลีกเลี่ยงการดาวน์โหลดซ้ำทุกครั้ง
ใช้การกำหนดเวอร์ชัน Bundle และส่วนหัวแคช
วิธีการทั่วไปในการแคชคือ
กำหนดให้เบราว์เซอร์แคชไฟล์เป็นเวลานานมาก (เช่น 1 ปี):
# Server header Cache-Control: max-age=31536000
หากไม่คุ้นเคยกับสิ่งที่
Cache-Control
ทำ โปรดดูเหตุการณ์ของ Jake Archibald โพสต์ที่ยอดเยี่ยม เกี่ยวกับการแคชที่ดีที่สุด แนวทางปฏิบัติที่ดีที่สุดและเปลี่ยนชื่อไฟล์เมื่อถูกเปลี่ยนเพื่อบังคับให้ดาวน์โหลดใหม่
<!-- Before the change --> <script src="./index-v15.js"></script> <!-- After the change --> <script src="./index-v16.js"></script>
วิธีนี้จะทำให้เบราว์เซอร์ดาวน์โหลดไฟล์ JS แคช และใช้ สำเนาที่แคชไว้ เบราว์เซอร์จะเชื่อมต่อกับเครือข่ายก็ต่อเมื่อชื่อไฟล์มีการเปลี่ยนแปลงเท่านั้น (หรือหากผ่านไป 1 ปีแล้ว)
คุณก็ทำเช่นเดียวกันใน Webpack แต่จะระบุหมายเลขเวอร์ชันแทนหมายเลขเวอร์ชัน
แฮชไฟล์ ในการรวมแฮชในชื่อไฟล์ ให้ใช้
[chunkhash]
:
// webpack.config.js
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.[chunkhash].js' // → bundle.8e0d62a03.js
}
};
หากคุณต้องการ
ส่งไฟล์ไปยังไคลเอ็นต์ ให้ใช้ HtmlWebpackPlugin
หรือ
WebpackManifestPlugin
HtmlWebpackPlugin
เป็น
เรียบง่าย แต่มีความยืดหยุ่นน้อยกว่า ในระหว่างการคอมไพล์ ปลั๊กอินนี้จะสร้าง
ไฟล์ HTML ที่มีทรัพยากรที่คอมไพล์ทั้งหมด หากตรรกะของเซิร์ฟเวอร์ไม่ตรงกัน
ซับซ้อน คุณควรจะเพียงพอแล้ว
<!-- index.html -->
<!DOCTYPE html>
<!-- ... -->
<script src="bundle.8e0d62a03.js"></script>
WebpackManifestPlugin
เป็นวิธีที่ยืดหยุ่นกว่า ซึ่งมีประโยชน์หากคุณมีส่วนของเซิร์ฟเวอร์ที่ซับซ้อน
ระหว่างบิลด์ ระบบจะสร้างไฟล์ JSON ที่มีการแมประหว่างชื่อไฟล์
ไม่มีแฮช และชื่อไฟล์มีแฮช ใช้ JSON นี้บนเซิร์ฟเวอร์เพื่อหาคำตอบ
ไฟล์ที่ควรใช้กับ
// manifest.json
{
"bundle.js": "bundle.8e0d62a03.js"
}
อ่านเพิ่มเติม
- Jake Archibald เกี่ยวกับการแคชที่ดีที่สุด แนวทางปฏิบัติ
แยกทรัพยากร Dependency และรันไทม์ออกเป็นไฟล์แยกต่างหาก
การอ้างอิง
ทรัพยากร Dependency ของแอปมีแนวโน้มที่จะเปลี่ยนแปลงน้อยกว่าโค้ดของแอปจริง หากคุณย้าย แยกให้เป็นไฟล์แยกต่างหาก เบราว์เซอร์จะสามารถแคชข้อมูลแยกกันได้ – และจะไม่ดาวน์โหลดแอปซ้ำทุกครั้งที่โค้ดของแอปเปลี่ยนแปลง
หากต้องการแยกทรัพยากร Dependency แยกเป็นกลุ่มย่อย ให้ทำ 3 ขั้นตอนดังนี้
แทนที่ชื่อไฟล์เอาต์พุตด้วย
[name].[chunkname].js
ดังนี้// webpack.config.js module.exports = { output: { // Before filename: 'bundle.[chunkhash].js', // After filename: '[name].[chunkhash].js' } };
เมื่อ Webpack สร้างแอป แอปจะแทนที่
[name]
ด้วยชื่อของกลุ่ม หากเราไม่เพิ่มส่วน[name]
เราจะ แยกความแตกต่างระหว่างส่วนเล็กๆ ด้วยแฮช ซึ่งเป็นเรื่องที่ค่อนข้างยาก!แปลงช่อง
entry
เป็นออบเจ็กต์// webpack.config.js module.exports = { // Before entry: './index.js', // After entry: { main: './index.js' } };
ในข้อมูลโค้ดนี้ "main" เป็นชื่อของกลุ่ม ชื่อนี้จะถูกแทนที่ใน สถานที่ของ
[name]
จากขั้นตอนที่ 1ในปัจจุบัน ถ้าคุณสร้างแอป กลุ่มนี้ประกอบด้วยโค้ดทั้งหมดของแอป เหมือนที่เรายังไม่ได้ทำตามขั้นตอนเหล่านี้ แต่การดำเนินการนี้จะเปลี่ยนไปภายในไม่กี่วินาที
ใน Webpack 4 ให้เพิ่มตัวเลือก
optimization.splitChunks.chunks: 'all'
ลงในการกำหนดค่า Webpack ดังนี้// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
ตัวเลือกนี้จะเปิดใช้การแยกโค้ดอัจฉริยะ เมื่อใช้แพลตฟอร์มนี้ Webpack จะแยกรหัสของผู้ให้บริการออกมา ไฟล์มีขนาดใหญ่กว่า 30 kB (ก่อนการลดขนาดและ gzip) และยังดึงโค้ดทั่วไปออกมา วิธีนี้มีประโยชน์หากบิลด์ของคุณสร้างแพ็กเกจหลายรายการ (เช่น หากคุณแยกแอปออกเป็นเส้นทาง)
ใน Webpack 3 ให้เพิ่มแท็ก
CommonsChunkPlugin
:// webpack.config.js (for webpack 3) module.exports = { plugins: [ new webpack.optimize.CommonsChunkPlugin({ // A name of the chunk that will include the dependencies. // This name is substituted in place of [name] from step 1 name: 'vendor', // A function that determines which modules to include into this chunk minChunks: module => module.context && module.context.includes('node_modules'), }) ] };
ปลั๊กอินนี้ใช้โมดูลทั้งหมดในเส้นทางที่มี
node_modules
และ ย้ายไปยังไฟล์แยกต่างหากที่ชื่อว่าvendor.[chunkhash].js
หลังจากการเปลี่ยนแปลงเหล่านี้ แต่ละบิลด์จะสร้างไฟล์ 2 ไฟล์แทนที่จะเป็นไฟล์เดียว ได้แก่ main.[chunkhash].js
และ
vendor.[chunkhash].js
(vendors~main.[chunkhash].js
สำหรับ Webpack 4) ในกรณีของ Webpack 4
ระบบอาจไม่สร้างกลุ่มผู้ให้บริการหากทรัพยากร Dependency มีขนาดเล็ก ซึ่งไม่มีปัญหา
$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
Asset Size Chunks Chunk Names
./main.00bab6fd3100008a42b0.js 82 kB 0 [emitted] main
./vendor.d9e134771799ecdf9483.js 47 kB 1 [emitted] vendor
เบราว์เซอร์จะแคชไฟล์เหล่านี้แยกต่างหาก และดาวน์โหลดเฉพาะโค้ดที่เปลี่ยนแปลงไปเท่านั้น
รหัสรันไทม์ของ Webpack
ขออภัย การดึงข้อมูลเฉพาะโค้ดผู้ให้บริการนั้นไม่เพียงพอ หากคุณพยายาม เปลี่ยนแปลงบางอย่างในโค้ดของแอป
// index.js
…
…
// E.g. add this:
console.log('Wat');
คุณจะสังเกตเห็นว่าแฮช vendor
จะเปลี่ยนไปด้วย
Asset Size Chunks Chunk Names
./vendor.d9e134771799ecdf9483.js 47 kB 1 [emitted] vendor
↓
Asset Size Chunks Chunk Names
./vendor.e6ea4504d61a1cc1c60b.js 47 kB 1 [emitted] vendor
ซึ่งเกิดขึ้นเนื่องจาก Bundle ของ Webpack นอกเหนือจากโค้ดของโมดูลแล้วจะมี a รันไทม์ – โค้ดสั้นๆ ที่จัดการการดำเนินการโมดูล เมื่อแบ่งโค้ดออกเป็นหลายๆ ไฟล์ โค้ดชิ้นนี้จะเริ่มรวมถึงการจับคู่ระหว่างรหัสกลุ่มกับ ไฟล์ที่เกี่ยวข้อง:
// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
"0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";
Webpack จะรวมรันไทม์นี้ไปยังกลุ่มที่สร้างล่าสุด ซึ่งก็คือ vendor
ในกรณีของเรา และทุกครั้งที่กลุ่มมีการเปลี่ยนแปลง โค้ดนี้ก็จะเปลี่ยนไปด้วย
ทำให้กลุ่ม vendor
ทั้งหมดเปลี่ยนไป
เราจะย้ายรันไทม์ไปไว้ในไฟล์แยกต่างหากเพื่อแก้ไขปัญหานี้ ใน Webpack 4 นี่คือ
ด้วยการเปิดใช้ตัวเลือก optimization.runtimeChunk
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
runtimeChunk: true
}
};
ใน Webpack 3 ให้ทำโดยการสร้างกลุ่มเปล่าเพิ่มเติมด้วย CommonsChunkPlugin
:
// webpack.config.js (for webpack 3)
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: module => module.context && module.context.includes('node_modules')
}),
// This plugin must come after the vendor one (because webpack
// includes runtime into the last chunk)
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
// minChunks: Infinity means that no app modules
// will be included into this chunk
minChunks: Infinity
})
]
};
หลังจากการเปลี่ยนแปลงเหล่านี้ แต่ละบิลด์จะสร้างไฟล์ 3 ไฟล์ ได้แก่
$ webpack
Hash: ac01483e8fec1fa70676
Version: webpack 3.8.1
Time: 3816ms
Asset Size Chunks Chunk Names
./main.00bab6fd3100008a42b0.js 82 kB 0 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 1 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
รวมเมตริกดังกล่าวไว้ใน index.html
ตามลำดับ เพียงเท่านี้ก็เสร็จแล้ว
<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>
<script src="./vendor.26886caf15818fa82dfa.js"></script>
<script src="./main.00bab6fd3100008a42b0.js"></script>
อ่านเพิ่มเติม
- คู่มือ Webpack เกี่ยวกับการแคชระยะยาว
- เอกสาร Webpack เกี่ยวกับรันไทม์ของ Webpack และ ไฟล์ Manifest
- "การใช้ประโยชน์สูงสุดจาก CommonsChunkPlugin"
- วิธีการทำงานของ
optimization.splitChunks
และoptimization.runtimeChunk
รันไทม์ของ Webpack ในบรรทัดเพื่อบันทึกคำขอ HTTP เพิ่มเติม
เพื่อให้งานดียิ่งขึ้น ให้ลองใส่รันไทม์ของ Webpack ไว้ใน HTML คำตอบ กล่าวคือ แทนที่จะเป็น
<!-- index.html -->
<script src="./runtime.79f17c27b335abc7aaf4.js"></script>
ทำสิ่งนี้
<!-- index.html -->
<script>
!function(e){function n(r){if(t[r])return t[r].exports;…}} ([]);
</script>
รันไทม์มีขนาดเล็ก และการแทรกไว้จะช่วยคุณบันทึกคำขอ HTTP ( สำคัญกับ HTTP/1 ไม่สำคัญกับ HTTP/2 แต่อาจยังมี )
มาดูวิธีกัน
หากคุณสร้าง HTML ด้วย HtmlWebpackPlugin
หากคุณใช้แท็ก HtmlWebpackPlugin เพื่อสร้าง ไฟล์ HTML InlineSourcePlugin คือสิ่งที่คุณต้องมี:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineSourcePlugin = require('html-webpack-inline-source-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
inlineSource: 'runtime~.+\\.js',
}),
new InlineSourcePlugin()
]
};
หากคุณสร้าง HTML โดยใช้ตรรกะเซิร์ฟเวอร์ที่กำหนดเอง
เมื่อใช้ Webpack 4
เพิ่ม
WebpackManifestPlugin
เพื่อทราบชื่อที่สร้างขึ้นของกลุ่มรันไทม์// webpack.config.js (for webpack 4) const ManifestPlugin = require('webpack-manifest-plugin'); module.exports = { plugins: [ new ManifestPlugin() ] };
บิลด์ที่มีปลั๊กอินนี้จะสร้างไฟล์ที่มีหน้าตาดังนี้
// manifest.json { "runtime~main.js": "runtime~main.8e0d62a03.js" }
แทรกเนื้อหาของกลุ่มรันไทม์ในลักษณะที่สะดวก เช่น ด้วย Node.js และ Express
// server.js const fs = require('fs'); const manifest = require('./manifest.json'); const runtimeContent = fs.readFileSync(manifest['runtime~main.js'], 'utf-8'); app.get('/', (req, res) => { res.send(` … <script>${runtimeContent}</script> … `); });
หรือ Webpack 3:
ทำให้ชื่อรันไทม์คงที่โดยการระบุ
filename
module.exports = { plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'runtime', minChunks: Infinity, filename: 'runtime.js' }) ] };
แทรกเนื้อหา
runtime.js
ไว้ในหน้าด้วยวิธีที่สะดวก เช่น ด้วย Node.js และ Express// server.js const fs = require('fs'); const runtimeContent = fs.readFileSync('./runtime.js', 'utf-8'); app.get('/', (req, res) => { res.send(` … <script>${runtimeContent}</script> … `); });
โค้ดแบบ Lazy Loading ที่คุณไม่จำเป็นต้องใช้ในตอนนี้
บางครั้งหน้าเว็บอาจมีส่วนสำคัญมากหรือน้อยดังต่อไปนี้
- หากคุณโหลดหน้าวิดีโอใน YouTube คุณจะให้ความสำคัญกับวิดีโอมากกว่า ความคิดเห็น ในวิดีโอนี้ วิดีโอมีความสำคัญมากกว่าความคิดเห็น
- ถ้าคุณเปิดบทความในเว็บไซต์ข่าว คุณจะให้ความสำคัญกับข้อความ บทความมากกว่าเรื่องโฆษณา ตรงนี้ข้อความสำคัญกว่าโฆษณา
ในกรณีดังกล่าว ให้ปรับปรุงประสิทธิภาพการโหลดเริ่มต้นโดยการดาวน์โหลดเฉพาะ
สิ่งสำคัญที่สุดก่อน แล้วค่อยโหลดส่วนที่เหลือทีหลัง ใช้เมธอด
import()
ฟังก์ชัน และ
code-splittingสำหรับส่วนนี้
// videoPlayer.js
export function renderVideoPlayer() { … }
// comments.js
export function renderComments() { … }
// index.js
import {renderVideoPlayer} from './videoPlayer';
renderVideoPlayer();
// …Custom event listener
onShowCommentsClick(() => {
import('./comments').then((comments) => {
comments.renderComments();
});
});
import()
ระบุว่าคุณต้องการโหลดโมดูลที่เฉพาะเจาะจงแบบไดนามิก วันและเวลา
Webpack เห็น import('./module.js')
จึงย้ายโมดูลนี้ไปยัง
chunk:
$ webpack
Hash: 39b2a53cb4e73f0dc5b2
Version: webpack 3.8.1
Time: 4273ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./main.f7e53d8e13e9a2745d6d.js 60 kB 1 [emitted] main
./vendor.4f14b6326a80f4752a98.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
และดาวน์โหลดเมื่อการดำเนินการถึงฟังก์ชัน import()
เท่านั้น
การดำเนินการนี้จะทำให้แพ็กเกจ main
เล็กลง ซึ่งจะลดเวลาที่ใช้ในการโหลดในช่วงแรก
ยิ่งไปกว่านั้น การแคชก็ช่วยปรับปรุงการแคชได้ กล่าวคือหากคุณเปลี่ยนโค้ดในส่วนหลัก
กลุ่มความคิดเห็นจะไม่ได้รับผลกระทบ
อ่านเพิ่มเติม
- เอกสาร Webpack สำหรับ
import()
ฟังก์ชัน - ข้อเสนอ JavaScript สำหรับการติดตั้งใช้งาน
import()
ไวยากรณ์
แยกโค้ดออกเป็นเส้นทางและหน้าเว็บ
หากแอปมีหลายเส้นทางหรือหน้าเว็บ แต่มีไฟล์ JS ไฟล์เดียวที่มี
โค้ด (กลุ่ม main
กลุ่มเดียว) เป็นไปได้ว่าคุณกำลังแสดงไบต์เพิ่มเติมกับ
คำขอแต่ละรายการ ตัวอย่างเช่น เมื่อผู้ใช้เข้าชมหน้าแรกของเว็บไซต์
ลูกค้าไม่จำเป็นต้องโหลดโค้ดเพื่อแสดงบทความที่อยู่ใน แต่หน้าเว็บจะโหลดขึ้นมา นอกจากนี้ หากผู้ใช้เข้าชมเฉพาะบ้านเสมอ และคุณทำการเปลี่ยนแปลงโค้ดบทความ Webpack จะทำให้ ทั้งชุด และผู้ใช้ต้องดาวน์โหลดแอปทั้งหมดใหม่อีกครั้ง
หากเราแบ่งแอปออกเป็นหลายหน้า (หรือเส้นทาง ถ้าเป็นแอปหน้าเดียว) ผู้ใช้ จะดาวน์โหลดเฉพาะโค้ดที่เกี่ยวข้องเท่านั้น นอกจากนี้ เบราว์เซอร์จะแคชโค้ดของแอป ที่ดีกว่า นั่นคือ หากคุณเปลี่ยนรหัสหน้าแรก Webpack จะทำให้เฉพาะ กลุ่มที่เกี่ยวข้อง
สำหรับแอปแบบหน้าเดียว
หากต้องการแยกแอปหน้าเว็บเดียวตามเส้นทาง ให้ใช้ import()
(โปรดดู "โค้ดการโหลดแบบ Lazy Loading
ที่คุณไม่ต้องการใช้ในขณะนี้") หากใช้เฟรมเวิร์ก
อาจมีโซลูชันอยู่แล้วในกรณีนี้
- "รหัส
การแยก"
ในเอกสารของ
react-router
(สำหรับ React) - "การโหลดแบบ Lazy Loading
เส้นทาง" ใน
เอกสารของ
vue-router
(สำหรับ Vue.js)
สำหรับแอปที่มีหลายหน้าแบบดั้งเดิม
หากต้องการแยกแอปแบบดั้งเดิมตามหน้า ให้ใช้รายการของ Webpack คะแนน ถ้าแอปมี ได้แก่ หน้าแรก หน้าบทความ และหน้าบัญชีผู้ใช้ ควรมีข้อมูล 3 รายการดังนี้
// webpack.config.js
module.exports = {
entry: {
home: './src/Home/index.js',
article: './src/Article/index.js',
profile: './src/Profile/index.js'
}
};
Webpack จะสร้างโครงสร้างทรัพยากร Dependency แยกต่างหากสำหรับไฟล์รายการแต่ละไฟล์ ชุดที่มีเฉพาะโมดูลที่รายการนั้นใช้
$ webpack
Hash: 318d7b8490a7382bf23b
Version: webpack 3.8.1
Time: 4273ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./home.91b9ed27366fe7e33d6a.js 18 kB 1 [emitted] home
./article.87a128755b16ac3294fd.js 32 kB 2 [emitted] article
./profile.de945dc02685f6166781.js 24 kB 3 [emitted] profile
./vendor.4f14b6326a80f4752a98.js 46 kB 4 [emitted] vendor
./runtime.318d7b8490a7382bf23b.js 1.45 kB 5 [emitted] runtime
ดังนั้น หากหน้าบทความเท่านั้นที่ใช้ Lodash แล้ว ชุดข้อมูล home
และ profile
จะไม่รวมอยู่ด้วย และผู้ใช้ไม่ต้องดาวน์โหลดไลบรารีนี้เมื่อ
เข้าชมหน้าแรก
แต่ต้นไม้ที่ต้องพึ่งพาแยกกันก็มีข้อเสียอยู่ หากจุดแรกเข้า 2 จุดใช้
Lodash และคุณไม่ได้ย้ายทรัพยากร Dependency ไปไว้ในแพ็กเกจผู้ให้บริการทั้ง 2 รายการ
คะแนนจะรวมสำเนาของ Lodash ในการแก้ปัญหานี้ ใน Webpack 4 ให้เพิ่มเมธอด
ตัวเลือก optimization.splitChunks.chunks: 'all'
ในการกำหนดค่า Webpack ของคุณ
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
ตัวเลือกนี้จะเปิดใช้การแยกโค้ดอัจฉริยะ เมื่อใช้ตัวเลือกนี้ Webpack จะทำงาน มองหาโค้ดทั่วไปและแยกออกมาเป็นไฟล์แยกต่างหาก
หรือใน Webpack 3 ให้ใช้ CommonsChunkPlugin
– จะย้ายทรัพยากร Dependency ทั่วไปไปยังไฟล์ที่ระบุใหม่ ดังนี้
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2 // 2 is the default value
})
]
};
ลองใช้ค่า minChunks
เพื่อหาค่าที่ดีที่สุดได้เลย โดยทั่วไป
คุณต้องการทำให้รูปย่อยๆ ไม่ใหญ่ แต่เพิ่มจำนวนขึ้นถ้าจำนวนไฟล์มีมากขึ้น สำหรับ
เช่น สำหรับ 3 กลุ่ม minChunks
อาจเป็น 2 แต่สำหรับ 30 กลุ่มอาจเป็น 8
– เพราะหากคุณคงระดับที่ 2 จะทำให้มีโมดูลที่มากเกินไปในไฟล์ทั่วไป
พองเกินไป
อ่านเพิ่มเติม
- เอกสาร Webpack เกี่ยวกับแนวคิดของการเข้าร่วม คะแนน
- เอกสาร Webpack เกี่ยวกับ CommonsChunkPlugin
- "การใช้ประโยชน์สูงสุดจาก CommonsChunkPlugin"
- วิธีการทำงานของ
optimization.splitChunks
และoptimization.runtimeChunk
ทำให้รหัสโมดูลเสถียรขึ้น
เมื่อสร้างโค้ด Webpack จะกำหนดรหัสให้กับแต่ละโมดูล หลังจากนั้น รหัสเหล่านี้จะ
ที่ใช้ไปใน require()
วินาทีภายในแพ็กเกจ โดยปกติคุณจะเห็นรหัสในเอาต์พุตของบิลด์
ก่อนเส้นทางโมดูล
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.8ecaf182f5c85b7a8199.js 22.5 kB 0 [emitted]
./main.4e50a16675574df6a9e9.js 60 kB 1 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
↓ ที่นี่
[0] ./index.js 29 kB {1} [built]
[2] (webpack)/buildin/global.js 488 bytes {2} [built]
[3] (webpack)/buildin/module.js 495 bytes {2} [built]
[4] ./comments.js 58 kB {0} [built]
[5] ./ads.js 74 kB {1} [built]
+ 1 hidden module
โดยค่าเริ่มต้น ระบบจะคำนวณรหัสโดยใช้ตัวนับ (เช่น โมดูลแรกมีรหัส 0 อันที่ 2 จะมีรหัส 1 เป็นต้น) ปัญหาก็คือ เมื่อคุณเพิ่ม โมดูลใหม่ โฆษณาอาจปรากฏที่กลางรายการโมดูล โดยเปลี่ยน โมดูลถัดไป รหัส:
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.5c82c0f337fcb22672b5.js 22 kB 0 [emitted]
./main.0c8b617dfc40c2827ae3.js 82 kB 1 [emitted] main
./vendor.26886caf15818fa82dfa.js 46 kB 2 [emitted] vendor
./runtime.79f17c27b335abc7aaf4.js 1.45 kB 3 [emitted] runtime
[0] ./index.js 29 kB {1} [built]
[2] (webpack)/buildin/global.js 488 bytes {2} [built]
[3] (webpack)/buildin/module.js 495 bytes {2} [built]
↓ เราได้เพิ่ม โมดูล...
[4] ./webPlayer.js 24 kB {1} [built]
↓ แล้วมาดูสิ่งที่ทำกันเลย! ตอนนี้ comments.js
มีรหัส 5 แทนที่จะเป็น 4
[5] ./comments.js 58 kB {0} [built]
↓ ads.js
ตอนนี้มีรหัส 6 จากเดิม 5 รายการ
[6] ./ads.js 74 kB {1} [built]
+ 1 hidden module
การดำเนินการนี้จะทำให้กลุ่มทั้งหมดที่มีหรือขึ้นอยู่กับโมดูลที่มีรหัสมีการเปลี่ยนแปลง เช่น
แม้ว่าโค้ดจริง
จะไม่มีการเปลี่ยนแปลงก็ตาม ในกรณีนี้ กลุ่ม 0
(กลุ่ม
ด้วย comments.js
) และ main
กลุ่ม (กลุ่มที่มีรหัสแอปอื่น) จะได้รับ
ใช้ไม่ได้ ขณะที่มีเพียง main
เท่านั้น
หากต้องการแก้ไขปัญหานี้ ให้เปลี่ยนวิธีคำนวณรหัสโมดูลโดยใช้
HashedModuleIdsPlugin
โดยแทนที่รหัสแบบอิงตามตัวนับด้วยแฮชของเส้นทางโมดูล ดังนี้
$ webpack
Hash: df3474e4f76528e3bbc9
Version: webpack 3.8.1
Time: 2150ms
Asset Size Chunks Chunk Names
./0.6168aaac8461862eab7a.js 22.5 kB 0 [emitted]
./main.a2e49a279552980e3b91.js 60 kB 1 [emitted] main
./vendor.ff9f7ea865884e6a84c8.js 46 kB 2 [emitted] vendor
./runtime.25f5d0204e4f77fa57a1.js 1.45 kB 3 [emitted] runtime
↓ ที่นี่
[3IRH] ./index.js 29 kB {1} [built]
[DuR2] (webpack)/buildin/global.js 488 bytes {2} [built]
[JkW7] (webpack)/buildin/module.js 495 bytes {2} [built]
[LbCc] ./webPlayer.js 24 kB {1} [built]
[lebJ] ./comments.js 58 kB {0} [built]
[02Tr] ./ads.js 74 kB {1} [built]
+ 1 hidden module
วิธีนี้จะทำให้รหัสของโมดูลเปลี่ยนแปลงก็ต่อเมื่อคุณเปลี่ยนชื่อหรือย้ายโมดูลเท่านั้น โมดูลใหม่จะไม่ส่งผลกระทบต่อโมดูลอื่นๆ รหัส
หากต้องการเปิดใช้ปลั๊กอิน ให้เพิ่มลงในส่วน plugins
ของการกำหนดค่า ดังนี้
// webpack.config.js
module.exports = {
plugins: [
new webpack.HashedModuleIdsPlugin()
]
};
อ่านเพิ่มเติม
- เอกสาร Webpack เกี่ยวกับ HashedModuleIdsPlugin
สรุป
- แคชชุดและแยกความแตกต่างระหว่างเวอร์ชันด้วยการเปลี่ยนชื่อ Bundle
- แยกแพ็กเกจออกเป็นโค้ดของแอป โค้ดของผู้ให้บริการ และรันไทม์
- แทรกรันไทม์เพื่อบันทึกคำขอ HTTP
- โหลดโค้ดที่ไม่สำคัญแบบ Lazy Loading ด้วย
import
- แยกโค้ดตามเส้นทาง/หน้าเพื่อหลีกเลี่ยงการโหลดรายการที่ไม่จำเป็น