چگونه وب پک به ذخیره دارایی کمک می کند
مورد بعدی (بعد از بهینه سازی اندازه برنامه که زمان بارگذاری برنامه را بهبود می بخشد، حافظه پنهان است. از آن برای نگه داشتن قسمت هایی از برنامه روی کلاینت استفاده کنید و از بارگیری مجدد هر بار آنها اجتناب کنید.
از نسخه سازی بسته نرم افزاری و هدرهای کش استفاده کنید
روش رایج انجام ذخیره سازی به این صورت است:
به مرورگر بگویید که یک فایل را برای مدت بسیار طولانی (مثلاً یک سال) کش کند:
# Server header Cache-Control: max-age=31536000
اگر با کارهایی که
Cache-Control
انجام می دهد آشنا نیستید، به پست عالی جیک آرچیبالد در مورد بهترین شیوه های ذخیره سازی کش مراجعه کنید.و پس از تغییر نام فایل را تغییر دهید تا بارگیری مجدد اجباری شود:
<!-- Before the change --> <script src="./index-v15.js"></script> <!-- After the change --> <script src="./index-v16.js"></script>
این رویکرد به مرورگر میگوید که فایل JS را دانلود کند، آن را کش کند و از کپی ذخیره شده استفاده کند. مرورگر فقط در صورت تغییر نام فایل (یا اگر یک سال بگذرد) وارد شبکه می شود.
با 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"
}
در ادامه مطلب
- جیک آرچیبالد درباره بهترین شیوه های ذخیره سازی در حافظه پنهان
وابستگی ها و زمان اجرا را در یک فایل جداگانه استخراج کنید
وابستگی ها
وابستگی های برنامه کمتر از کد واقعی برنامه تغییر می کند. اگر آنها را به یک فایل جداگانه منتقل کنید، مرورگر میتواند آنها را به طور جداگانه کش کند - و هر بار که کد برنامه تغییر میکند آنها را دوباره دانلود نمیکند.
برای استخراج وابستگی ها به یک تکه جداگانه، سه مرحله را انجام دهید:
نام فایل خروجی را با
[name].[chunkname].js
:// webpack.config.js module.exports = { output: { // Before filename: 'bundle.[chunkhash].js', // After filename: '[name].[chunkhash].js' } };
وقتی وبپک برنامه را میسازد،
[name]
را با نام یک تکه جایگزین میکند. اگر قسمت[name]
را اضافه نکنیم، باید بین تکهها بر اساس هش آنها تفاوت قائل شویم – که بسیار سخت است!فیلد
entry
را به یک شی تبدیل کنید:// webpack.config.js module.exports = { // Before entry: './index.js', // After entry: { main: './index.js' } };
در این قطعه، "main" نام یک تکه است. این نام به جای
[name]
از مرحله 1 جایگزین می شود.در حال حاضر، اگر برنامه را بسازید، این بخش شامل کل کد برنامه خواهد بود - درست مثل ما که این مراحل را انجام ندادهایم. اما این در یک ثانیه تغییر خواهد کرد.
در بسته وب 4 ، گزینه
optimization.splitChunks.chunks: 'all'
به پیکربندی بسته وب خود اضافه کنید:// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
این گزینه تقسیم کد هوشمند را فعال می کند. با استفاده از آن، وبپک کد فروشنده را در صورتی که از 30 کیلوبایت بزرگتر شود (قبل از کوچکسازی و gzip) استخراج میکند. همچنین کد رایج را استخراج میکند - این در صورتی مفید است که بیلد شما چندین باندل تولید کند (مثلاً اگر برنامه خود را به مسیرها تقسیم کنید ).
در بسته وب 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
.
پس از این تغییرات، هر بیلد به جای یک فایل، دو فایل تولید میکند: main.[chunkhash].js
و vendor.[chunkhash].js
( vendors~main.[chunkhash].js
برای وبپک 4). در مورد بسته وب 4، اگر وابستگی ها کوچک باشند، ممکن است بسته فروشنده ایجاد نشود - و این خوب است:
$ 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
مرورگر این فایلها را جداگانه ذخیره میکند – و فقط کدهایی را که تغییر میکنند دوباره دانلود میکند.
کد زمان اجرا وب پک
متأسفانه، استخراج فقط کد فروشنده کافی نیست. اگر میخواهید چیزی را در کد برنامه تغییر دهید:
// 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
این به این دلیل اتفاق میافتد که بسته وب بسته، جدا از کد ماژولها، دارای یک زمان اجرا است - یک قطعه کد کوچک که اجرای ماژول را مدیریت میکند. هنگامی که کد را به چندین فایل تقسیم می کنید، این قطعه کد شامل نقشه برداری بین شناسه های تکه و فایل های مربوطه شروع می شود:
// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
"0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";
Webpack این زمان اجرا را در آخرین قطعه تولید شده، که در مورد ما vendor
است، شامل می شود. و هر بار که هر تکه ای تغییر می کند، این قطعه کد نیز تغییر می کند و باعث می شود کل قطعه vendor
تغییر کند.
برای حل این مشکل، اجازه دهید زمان اجرا را به یک فایل جداگانه منتقل کنیم. در وب پک 4، این با فعال کردن گزینه optimization.runtimeChunk
به دست می آید:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
runtimeChunk: true
}
};
در وب پک 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
})
]
};
پس از این تغییرات، هر بیلد سه فایل تولید می کند:
$ 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 درباره زمان اجرا و مانیفست پک وب
- "بهره گیری از CommonsChunkPlugin"
- نحوه کار
optimization.splitChunks
وoptimization.runtimeChunk
زمان اجرای بسته وب داخلی برای ذخیره یک درخواست HTTP اضافی
برای بهتر کردن اوضاع، سعی کنید زمان اجرا بسته وب را در پاسخ 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 را با استفاده از منطق سرور سفارشی تولید می کنید
با وب پک 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> … `); });
یا با وب پک 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-load که در حال حاضر به آن نیاز ندارید
گاهی اوقات، یک صفحه دارای بخشهای مهمتر و کمتری است:
- اگر صفحه ویدیویی را در یوتیوب بارگذاری کنید، بیشتر به ویدیو اهمیت می دهید تا نظرات. در اینجا، ویدیو مهمتر از نظرات است.
- اگر مقاله ای را در یک سایت خبری باز کنید، بیشتر به متن مقاله اهمیت می دهید تا تبلیغات. در اینجا متن مهمتر از تبلیغات است.
در چنین مواردی، با دانلود فقط مهمترین موارد در ابتدا و بارگیری تنبلی قسمتهای باقیمانده، عملکرد بارگذاری اولیه را بهبود بخشید. برای این کار از تابع import()
و تقسیم کد استفاده کنید:
// 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')
میبیند، این ماژول را به یک تکه جداگانه منتقل میکند:
$ 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()
- پیشنهاد جاوا اسکریپت برای پیاده سازی
import()
کد را به مسیرها و صفحات تقسیم کنید
اگر برنامه شما چندین مسیر یا صفحه دارد، اما تنها یک فایل JS با کد (یک تکه main
) وجود دارد، احتمالاً در هر درخواست بایتهای اضافی ارائه میکنید. به عنوان مثال، هنگامی که یک کاربر از صفحه اصلی سایت شما بازدید می کند:
آنها نیازی به بارگذاری کد برای ارائه مقاله ای که در صفحه دیگری است ندارند - اما آنها آن را بارگذاری می کنند. علاوه بر این، اگر کاربر همیشه فقط از صفحه اصلی بازدید کند، و شما تغییری در کد مقاله ایجاد کنید، بسته وب کل بسته نرم افزاری را باطل می کند - و کاربر باید کل برنامه را دوباره دانلود کند.
اگر برنامه را به صفحات (یا مسیرها، اگر یک برنامه تک صفحه ای است) تقسیم کنیم، کاربر فقط کد مربوطه را دانلود می کند. بعلاوه، مرورگر کد برنامه را بهتر کش میکند: اگر کد صفحه اصلی را تغییر دهید، بسته وب فقط تکه مربوطه را باطل میکند.
برای برنامه های تک صفحه ای
برای تقسیم برنامههای تک صفحهای بر اساس مسیرها، از import()
استفاده کنید (به بخش «کد تنبل بارگذاری که در حال حاضر به آن نیاز ندارید» مراجعه کنید). اگر از یک فریم ورک استفاده می کنید، ممکن است یک راه حل موجود برای این کار داشته باشد:
- "Code Splitting" در اسناد
react-router
(برای React) - "مسیرهای بارگذاری تنبل" در اسناد
vue-router
(برای Vue.js)
برای برنامه های سنتی چند صفحه ای
برای تقسیم برنامه های سنتی بر اساس صفحات، از نقاط ورودی وب پک استفاده کنید. اگر برنامه شما دارای سه نوع صفحه است: صفحه اصلی، صفحه مقاله و صفحه حساب کاربری، - باید سه ورودی داشته باشد:
// webpack.config.js
module.exports = {
entry: {
home: './src/Home/index.js',
article: './src/Article/index.js',
profile: './src/Profile/index.js'
}
};
برای هر فایل ورودی، وبپک یک درخت وابستگی مجزا میسازد و بستهای ایجاد میکند که فقط شامل ماژولهایی است که توسط آن ورودی استفاده میشوند:
$ 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
شامل آن نمیشود - و کاربر مجبور نیست این کتابخانه را هنگام بازدید از صفحه اصلی دانلود کند.
درختهای وابستگی مجزا دارای معایبی هستند. اگر دو نقطه ورودی از Lodash استفاده میکنند، و شما وابستگیهای خود را به یک بسته فروشنده منتقل نکردهاید، هر دو نقطه ورودی یک کپی از Lodash را شامل میشوند. برای حل این مشکل، در بسته وب 4، گزینه optimization.splitChunks.chunks: 'all'
را به پیکربندی بسته وب خود اضافه کنید:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
این گزینه تقسیم کد هوشمند را فعال می کند. با استفاده از این گزینه، وب پک به طور خودکار به دنبال کدهای رایج می گردد و آن را در فایل های جداگانه استخراج می کند.
یا در بسته وب 3 از CommonsChunkPlugin
استفاده کنید – وابستگی های رایج را به یک فایل مشخص شده جدید منتقل می کند:
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
شناسه های ماژول را پایدارتر کنید
هنگام ساخت کد، وب پک به هر ماژول یک شناسه اختصاص می دهد. بعداً، این شناسه ها در 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
بهطور پیشفرض، شناسهها با استفاده از یک شمارنده محاسبه میشوند (یعنی ماژول اول دارای ID 0، ماژول دوم دارای ID 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
اکنون به جای 4 دارای شناسه 5 است
[5] ./comments.js 58 kB {0} [built]
↓ ads.js
اکنون به جای 5 دارای شناسه 6 است
[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
جمع بندی
- باندل را کش کش کنید و با تغییر نام بسته، بین نسخه ها تفاوت قائل شوید
- بسته نرم افزاری را به کد برنامه، کد فروشنده و زمان اجرا تقسیم کنید
- برای ذخیره درخواست HTTP، زمان اجرا را به صورت درون خطی کنید
- کد غیر بحرانی بارگذاری تنبل با
import
- برای جلوگیری از بارگیری موارد غیر ضروری، کد را بر اساس مسیرها/صفحات تقسیم کنید
چگونه وب پک به ذخیره دارایی کمک می کند
مورد بعدی (بعد از بهینه سازی اندازه برنامه که زمان بارگذاری برنامه را بهبود می بخشد، حافظه پنهان است. از آن برای نگه داشتن قسمت هایی از برنامه روی کلاینت استفاده کنید و از بارگیری مجدد هر بار آنها اجتناب کنید.
از نسخه سازی بسته نرم افزاری و هدرهای کش استفاده کنید
روش رایج انجام ذخیره سازی به این صورت است:
به مرورگر بگویید که یک فایل را برای مدت بسیار طولانی (مثلاً یک سال) کش کند:
# Server header Cache-Control: max-age=31536000
اگر با کارهایی که
Cache-Control
انجام می دهد آشنا نیستید، به پست عالی جیک آرچیبالد در مورد بهترین شیوه های ذخیره سازی کش مراجعه کنید.و پس از تغییر نام فایل را تغییر دهید تا بارگیری مجدد اجباری شود:
<!-- Before the change --> <script src="./index-v15.js"></script> <!-- After the change --> <script src="./index-v16.js"></script>
این رویکرد به مرورگر میگوید که فایل JS را دانلود کند، آن را کش کند و از کپی ذخیره شده استفاده کند. مرورگر فقط در صورت تغییر نام فایل (یا اگر یک سال بگذرد) وارد شبکه می شود.
با 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"
}
در ادامه مطلب
- جیک آرچیبالد درباره بهترین شیوه های ذخیره سازی در حافظه پنهان
وابستگی ها و زمان اجرا را در یک فایل جداگانه استخراج کنید
وابستگی ها
وابستگی های برنامه کمتر از کد واقعی برنامه تغییر می کند. اگر آنها را به یک فایل جداگانه منتقل کنید، مرورگر میتواند آنها را به طور جداگانه کش کند - و هر بار که کد برنامه تغییر میکند آنها را دوباره دانلود نمیکند.
برای استخراج وابستگی ها به یک تکه جداگانه، سه مرحله را انجام دهید:
نام فایل خروجی را با
[name].[chunkname].js
:// webpack.config.js module.exports = { output: { // Before filename: 'bundle.[chunkhash].js', // After filename: '[name].[chunkhash].js' } };
وقتی وبپک برنامه را میسازد،
[name]
را با نام یک تکه جایگزین میکند. اگر قسمت[name]
را اضافه نکنیم، باید بین تکهها بر اساس هش آنها تفاوت قائل شویم – که بسیار سخت است!فیلد
entry
را به یک شی تبدیل کنید:// webpack.config.js module.exports = { // Before entry: './index.js', // After entry: { main: './index.js' } };
در این قطعه، "main" نام یک تکه است. این نام به جای
[name]
از مرحله 1 جایگزین می شود.در حال حاضر، اگر برنامه را بسازید، این بخش شامل کل کد برنامه خواهد بود - درست مثل ما که این مراحل را انجام ندادهایم. اما این در یک ثانیه تغییر خواهد کرد.
در بسته وب 4 ، گزینه
optimization.splitChunks.chunks: 'all'
به پیکربندی بسته وب خود اضافه کنید:// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
این گزینه تقسیم کد هوشمند را فعال می کند. با استفاده از آن، وبپک کد فروشنده را در صورتی که از 30 کیلوبایت بزرگتر شود (قبل از کوچکسازی و gzip) استخراج میکند. همچنین کد رایج را استخراج میکند - این در صورتی مفید است که بیلد شما چندین باندل تولید کند (مثلاً اگر برنامه خود را به مسیرها تقسیم کنید ).
در بسته وب 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
.
پس از این تغییرات، هر بیلد به جای یک فایل، دو فایل تولید میکند: main.[chunkhash].js
و vendor.[chunkhash].js
( vendors~main.[chunkhash].js
برای وبپک 4). در مورد بسته وب 4، اگر وابستگی ها کوچک باشند، ممکن است بسته فروشنده ایجاد نشود - و این خوب است:
$ 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
مرورگر این فایلها را جداگانه ذخیره میکند – و فقط کدهایی را که تغییر میکنند دوباره دانلود میکند.
کد زمان اجرا وب پک
متأسفانه، استخراج فقط کد فروشنده کافی نیست. اگر میخواهید چیزی را در کد برنامه تغییر دهید:
// 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
این به این دلیل اتفاق میافتد که بسته وب بسته، جدا از کد ماژولها، دارای یک زمان اجرا است - یک قطعه کد کوچک که اجرای ماژول را مدیریت میکند. هنگامی که کد را به چندین فایل تقسیم می کنید، این قطعه کد شامل نقشه برداری بین شناسه های تکه و فایل های مربوطه شروع می شود:
// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
"0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";
Webpack این زمان اجرا را در آخرین قطعه تولید شده، که در مورد ما vendor
است، شامل می شود. و هر بار که هر تکه ای تغییر می کند، این قطعه کد نیز تغییر می کند و باعث می شود کل قطعه vendor
تغییر کند.
برای حل این مشکل، اجازه دهید زمان اجرا را به یک فایل جداگانه منتقل کنیم. در وب پک 4، این با فعال کردن گزینه optimization.runtimeChunk
به دست می آید:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
runtimeChunk: true
}
};
در وب پک 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
})
]
};
پس از این تغییرات، هر بیلد سه فایل تولید می کند:
$ 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 درباره زمان اجرا و مانیفست پک وب
- "بهره گیری از CommonsChunkPlugin"
- نحوه کار
optimization.splitChunks
وoptimization.runtimeChunk
زمان اجرای بسته وب داخلی برای ذخیره یک درخواست HTTP اضافی
برای بهتر کردن اوضاع، سعی کنید زمان اجرا بسته وب را در پاسخ 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 را با استفاده از منطق سرور سفارشی تولید می کنید
با وب پک 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> … `); });
یا با وب پک 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-load که در حال حاضر به آن نیاز ندارید
گاهی اوقات، یک صفحه دارای بخشهای مهمتر و کمتری است:
- اگر صفحه ویدیویی را در یوتیوب بارگذاری کنید، بیشتر به ویدیو اهمیت می دهید تا نظرات. در اینجا، ویدیو مهمتر از نظرات است.
- اگر مقاله ای را در یک سایت خبری باز کنید، بیشتر به متن مقاله اهمیت می دهید تا تبلیغات. در اینجا متن مهمتر از تبلیغات است.
در چنین مواردی، با دانلود فقط مهمترین موارد در ابتدا و بارگیری تنبلی قسمتهای باقیمانده، عملکرد بارگذاری اولیه را بهبود بخشید. برای این کار از تابع import()
و تقسیم کد استفاده کنید:
// 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')
میبیند، این ماژول را به یک تکه جداگانه منتقل میکند:
$ 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()
- پیشنهاد جاوا اسکریپت برای پیاده سازی
import()
کد را به مسیرها و صفحات تقسیم کنید
اگر برنامه شما چندین مسیر یا صفحه دارد، اما تنها یک فایل JS با کد (یک تکه main
) وجود دارد، احتمالاً در هر درخواست بایتهای اضافی ارائه میکنید. به عنوان مثال، هنگامی که یک کاربر از صفحه اصلی سایت شما بازدید می کند:
آنها نیازی به بارگذاری کد برای ارائه مقاله ای که در صفحه دیگری است ندارند - اما آنها آن را بارگذاری می کنند. علاوه بر این، اگر کاربر همیشه فقط از صفحه اصلی بازدید کند، و شما تغییری در کد مقاله ایجاد کنید، بسته وب کل بسته نرم افزاری را باطل می کند - و کاربر باید کل برنامه را دوباره دانلود کند.
اگر برنامه را به صفحات (یا مسیرها، اگر یک برنامه تک صفحه ای است) تقسیم کنیم، کاربر فقط کد مربوطه را دانلود می کند. بعلاوه، مرورگر کد برنامه را بهتر کش میکند: اگر کد صفحه اصلی را تغییر دهید، بسته وب فقط تکه مربوطه را باطل میکند.
برای برنامه های تک صفحه ای
برای تقسیم برنامههای تک صفحهای بر اساس مسیرها، از import()
استفاده کنید (به بخش «کد تنبل بارگذاری که در حال حاضر به آن نیاز ندارید» مراجعه کنید). اگر از یک فریم ورک استفاده می کنید، ممکن است یک راه حل موجود برای این کار داشته باشد:
- "Code Splitting" در اسناد
react-router
(برای React) - "مسیرهای بارگذاری تنبل" در اسناد
vue-router
(برای Vue.js)
برای برنامه های سنتی چند صفحه ای
برای تقسیم برنامه های سنتی بر اساس صفحات، از نقاط ورودی وب پک استفاده کنید. اگر برنامه شما دارای سه نوع صفحه است: صفحه اصلی، صفحه مقاله و صفحه حساب کاربری، - باید سه ورودی داشته باشد:
// webpack.config.js
module.exports = {
entry: {
home: './src/Home/index.js',
article: './src/Article/index.js',
profile: './src/Profile/index.js'
}
};
برای هر فایل ورودی، وبپک یک درخت وابستگی مجزا میسازد و بستهای ایجاد میکند که فقط شامل ماژولهایی است که توسط آن ورودی استفاده میشوند:
$ 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
شامل آن نمیشود - و کاربر مجبور نیست این کتابخانه را هنگام بازدید از صفحه اصلی دانلود کند.
درختهای وابستگی مجزا دارای معایبی هستند. اگر دو نقطه ورودی از Lodash استفاده میکنند، و شما وابستگیهای خود را به یک بسته فروشنده منتقل نکردهاید، هر دو نقطه ورودی یک کپی از Lodash را شامل میشوند. برای حل این مشکل، در بسته وب 4، گزینه optimization.splitChunks.chunks: 'all'
را به پیکربندی بسته وب خود اضافه کنید:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
این گزینه تقسیم کد هوشمند را فعال می کند. با استفاده از این گزینه، وب پک به طور خودکار به دنبال کدهای رایج می گردد و آن را در فایل های جداگانه استخراج می کند.
یا در بسته وب 3 از CommonsChunkPlugin
استفاده کنید – وابستگی های رایج را به یک فایل مشخص شده جدید منتقل می کند:
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
شناسه های ماژول را پایدارتر کنید
هنگام ساخت کد، وب پک به هر ماژول یک شناسه اختصاص می دهد. بعداً، این شناسه ها در 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
بهطور پیشفرض، شناسهها با استفاده از یک شمارنده محاسبه میشوند (یعنی ماژول اول دارای ID 0، ماژول دوم دارای ID 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
اکنون به جای 4 دارای شناسه 5 است
[5] ./comments.js 58 kB {0} [built]
↓ ads.js
اکنون به جای 5 دارای شناسه 6 است
[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
جمع بندی
- باندل را کش کش کنید و با تغییر نام بسته، بین نسخه ها تفاوت قائل شوید
- بسته نرم افزاری را به کد برنامه، کد فروشنده و زمان اجرا تقسیم کنید
- برای ذخیره درخواست HTTP، زمان اجرا را به صورت درون خطی کنید
- کد غیر بحرانی بارگذاری تنبل با
import
- برای جلوگیری از بارگیری موارد غیر ضروری، کد را بر اساس مسیرها/صفحات تقسیم کنید
چگونه وب پک به ذخیره دارایی کمک می کند
مورد بعدی (بعد از بهینه سازی اندازه برنامه که زمان بارگذاری برنامه را بهبود می بخشد، حافظه پنهان است. از آن برای نگه داشتن قسمت هایی از برنامه روی کلاینت استفاده کنید و از بارگیری مجدد هر بار آنها اجتناب کنید.
از نسخه سازی بسته نرم افزاری و هدرهای کش استفاده کنید
روش رایج انجام ذخیره سازی به این صورت است:
به مرورگر بگویید که یک فایل را برای مدت بسیار طولانی (مثلاً یک سال) کش کند:
# Server header Cache-Control: max-age=31536000
اگر با کارهایی که
Cache-Control
انجام می دهد آشنا نیستید، به پست عالی جیک آرچیبالد در مورد بهترین شیوه های ذخیره سازی کش مراجعه کنید.و پس از تغییر نام فایل را تغییر دهید تا بارگیری مجدد اجباری شود:
<!-- Before the change --> <script src="./index-v15.js"></script> <!-- After the change --> <script src="./index-v16.js"></script>
این رویکرد به مرورگر میگوید که فایل JS را دانلود کند، آن را کش کند و از کپی ذخیره شده استفاده کند. مرورگر فقط در صورت تغییر نام فایل (یا اگر یک سال بگذرد) وارد شبکه می شود.
با 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"
}
در ادامه مطلب
- جیک آرچیبالد درباره بهترین شیوه های ذخیره سازی در حافظه پنهان
وابستگی ها و زمان اجرا را در یک فایل جداگانه استخراج کنید
وابستگی ها
وابستگی های برنامه کمتر از کد واقعی برنامه تغییر می کند. اگر آنها را به یک فایل جداگانه منتقل کنید، مرورگر میتواند آنها را به طور جداگانه کش کند - و هر بار که کد برنامه تغییر میکند آنها را دوباره دانلود نمیکند.
برای استخراج وابستگی ها به یک تکه جداگانه، سه مرحله را انجام دهید:
نام فایل خروجی را با
[name].[chunkname].js
:// webpack.config.js module.exports = { output: { // Before filename: 'bundle.[chunkhash].js', // After filename: '[name].[chunkhash].js' } };
وقتی وبپک برنامه را میسازد،
[name]
را با نام یک تکه جایگزین میکند. اگر قسمت[name]
را اضافه نکنیم، باید بین تکهها بر اساس هش آنها تفاوت قائل شویم – که بسیار سخت است!فیلد
entry
را به یک شی تبدیل کنید:// webpack.config.js module.exports = { // Before entry: './index.js', // After entry: { main: './index.js' } };
در این قطعه، "main" نام یک تکه است. این نام به جای
[name]
از مرحله 1 جایگزین می شود.در حال حاضر، اگر برنامه را بسازید، این بخش شامل کل کد برنامه خواهد بود - درست مثل ما که این مراحل را انجام ندادهایم. اما این در یک ثانیه تغییر خواهد کرد.
در بسته وب 4 ، گزینه
optimization.splitChunks.chunks: 'all'
به پیکربندی بسته وب خود اضافه کنید:// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
این گزینه تقسیم کد هوشمند را فعال می کند. با استفاده از آن، وبپک کد فروشنده را در صورتی که از 30 کیلوبایت بزرگتر شود (قبل از کوچکسازی و gzip) استخراج میکند. همچنین کد رایج را استخراج میکند - این در صورتی مفید است که بیلد شما چندین باندل تولید کند (مثلاً اگر برنامه خود را به مسیرها تقسیم کنید ).
در بسته وب 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
.
پس از این تغییرات، هر بیلد به جای یک فایل، دو فایل تولید میکند: main.[chunkhash].js
و vendor.[chunkhash].js
( vendors~main.[chunkhash].js
برای وبپک 4). در مورد وب پک 4، اگر وابستگی ها کوچک باشند، ممکن است بسته فروشنده ایجاد نشود - و این خوب است:
$ 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
مرورگر این فایلها را جداگانه ذخیره میکند – و فقط کدهایی را که تغییر میکنند دوباره دانلود میکند.
کد زمان اجرا وب پک
متأسفانه، استخراج فقط کد فروشنده کافی نیست. اگر میخواهید چیزی را در کد برنامه تغییر دهید:
// 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
این به این دلیل اتفاق میافتد که بسته وب بسته، جدا از کد ماژولها، دارای یک زمان اجرا است - یک قطعه کد کوچک که اجرای ماژول را مدیریت میکند. هنگامی که کد را به چندین فایل تقسیم می کنید، این قطعه کد شامل نقشه برداری بین شناسه های تکه و فایل های مربوطه شروع می شود:
// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
"0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";
Webpack این زمان اجرا را در آخرین قطعه تولید شده، که در مورد ما vendor
است، شامل می شود. و هر بار که هر تکه ای تغییر می کند، این قطعه کد نیز تغییر می کند و باعث می شود کل قطعه vendor
تغییر کند.
برای حل این مشکل، اجازه دهید زمان اجرا را به یک فایل جداگانه منتقل کنیم. در وب پک 4، این با فعال کردن گزینه optimization.runtimeChunk
به دست می آید:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
runtimeChunk: true
}
};
در وب پک 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
})
]
};
پس از این تغییرات، هر بیلد سه فایل تولید می کند:
$ 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 درباره زمان اجرا و مانیفست پک وب
- "بهره گیری از CommonsChunkPlugin"
- نحوه کار
optimization.splitChunks
وoptimization.runtimeChunk
زمان اجرای بسته وب داخلی برای ذخیره یک درخواست HTTP اضافی
برای بهتر کردن اوضاع، سعی کنید زمان اجرا بسته وب را در پاسخ 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 را با استفاده از منطق سرور سفارشی تولید می کنید
با وب پک 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> … `); });
یا با وب پک 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-load که در حال حاضر به آن نیاز ندارید
گاهی اوقات، یک صفحه دارای بخشهای مهمتر و کمتری است:
- اگر صفحه ویدیویی را در یوتیوب بارگذاری کنید، بیشتر به ویدیو اهمیت می دهید تا نظرات. در اینجا، ویدیو مهمتر از نظرات است.
- اگر مقاله ای را در یک سایت خبری باز کنید، بیشتر به متن مقاله اهمیت می دهید تا تبلیغات. در اینجا متن مهمتر از تبلیغات است.
در چنین مواردی، با دانلود فقط مهمترین موارد در ابتدا و بارگیری تنبلی قسمتهای باقیمانده، عملکرد بارگذاری اولیه را بهبود بخشید. برای این کار از تابع import()
و تقسیم کد استفاده کنید:
// 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')
میبیند، این ماژول را به یک تکه جداگانه منتقل میکند:
$ 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()
- پیشنهاد جاوا اسکریپت برای پیاده سازی
import()
کد را به مسیرها و صفحات تقسیم کنید
اگر برنامه شما چندین مسیر یا صفحه دارد، اما تنها یک فایل JS با کد (یک تکه main
) وجود دارد، احتمالاً در هر درخواست بایتهای اضافی ارائه میکنید. به عنوان مثال، هنگامی که یک کاربر از صفحه اصلی سایت شما بازدید می کند:
آنها نیازی به بارگذاری کد برای ارائه مقاله ای که در صفحه دیگری است ندارند - اما آنها آن را بارگذاری می کنند. علاوه بر این، اگر کاربر همیشه فقط از صفحه اصلی بازدید کند، و شما تغییری در کد مقاله ایجاد کنید، بسته وب کل بسته نرم افزاری را باطل می کند - و کاربر باید کل برنامه را دوباره دانلود کند.
اگر برنامه را به صفحات (یا مسیرها، اگر یک برنامه تک صفحه ای است) تقسیم کنیم، کاربر فقط کد مربوطه را دانلود می کند. بعلاوه، مرورگر کد برنامه را بهتر کش میکند: اگر کد صفحه اصلی را تغییر دهید، بسته وب فقط تکه مربوطه را باطل میکند.
برای برنامه های تک صفحه ای
برای تقسیم برنامه های تک صفحه ای بر اساس مسیرها ، از import()
استفاده کنید (به بخش "کد بار تنبل که در حال حاضر نیازی به آن ندارید" مراجعه کنید). اگر از یک چارچوب استفاده می کنید ، ممکن است یک راه حل موجود برای این کار داشته باشد:
- "تقسیم کد" در اسناد
react-router
(برای واکنش) - "مسیرهای بارگیری تنبل" در اسناد
vue-router
(برای Vue.js)
برای برنامه های سنتی چند صفحه ای
برای تقسیم برنامه های سنتی بر اساس صفحات ، از نقاط ورود به وب استفاده کنید. اگر برنامه شما سه نوع صفحه دارد: صفحه اصلی ، صفحه مقاله و صفحه حساب کاربری ، - باید سه مدخل داشته باشد:
// webpack.config.js
module.exports = {
entry: {
home: './src/Home/index.js',
article: './src/Article/index.js',
profile: './src/Profile/index.js'
}
};
برای هر فایل ورودی ، صفحه وب یک درخت وابستگی جداگانه ایجاد می کند و یک بسته نرم افزاری تولید می کند که فقط ماژول هایی را شامل می شود که توسط آن ورودی استفاده می شود:
$ 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
آن را شامل نمی شوند - و کاربر هنگام مراجعه به صفحه اصلی مجبور به بارگیری این کتابخانه نخواهد بود.
درختان وابستگی جداگانه اشکال خود را دارند. اگر دو نقطه ورود از Lodash استفاده کنید ، و وابستگی های خود را به بسته نرم افزاری فروشنده منتقل نکرده اید ، هر دو نقطه ورود شامل یک نسخه از Lodash است. برای حل این مسئله ، در Webpack 4 ، optimization.splitChunks.chunks: 'all'
به پیکربندی وب خود اضافه کنید:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
این گزینه تقسیم کد هوشمند را امکان پذیر می کند. با استفاده از این گزینه ، Webpack به طور خودکار به دنبال کد مشترک و استخراج آن در پرونده های جداگانه است.
یا در وب 3 ، از CommonsChunkPlugin
استفاده کنید - وابستگی های مشترک را به یک پرونده مشخص شده جدید منتقل می کند:
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2 // 2 is the default value
})
]
};
برای یافتن بهترین مورد ، با ارزش minChunks
بازی کنید. به طور کلی ، شما می خواهید آن را کوچک نگه دارید ، اما در صورت افزایش تعداد تکه ها افزایش می یابد. به عنوان مثال ، برای 3 قطعه ، minChunks
ممکن است 2 باشند ، اما برای 30 قطعه ، ممکن است 8 باشد - زیرا اگر آن را در 2 نگه دارید ، ماژول های زیادی وارد پرونده مشترک می شوند و بیش از حد آن را باد می کنند.
در ادامه مطلب
- اسناد وب در مورد مفهوم نقاط ورود
- اسناد وب در مورد Commonschunkplugin
- "بیشترین استفاده را از Commonschunkplugin"
- چگونه
optimization.splitChunks
وoptimization.runtimeChunk
کار 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 ، مورد دوم دارای شناسه 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
اکنون به جای 4 شناسه 5 دارد
[5] ./comments.js 58 kB {0} [built]
↓ ads.js
اکنون به جای 5 شناسه 6 دارد
[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()
]
};
در ادامه مطلب
- اسناد وب در مورد hashedmoduleidsplugin
جمع بندی
- بسته نرم افزاری را ذخیره کرده و با تغییر نام بسته نرم افزاری بین نسخه ها تمایز قائل شوید
- بسته نرم افزاری را به کد برنامه ، کد فروشنده و زمان اجرا تقسیم کنید
- زمان اجرا را برای ذخیره درخواست HTTP وارد کنید
- کد غیر بحرانی بار تنبل با
import
- برای جلوگیری از بارگیری چیزهای غیر ضروری ، کد را توسط مسیرها/صفحات تقسیم کنید
چگونه Webpack به حافظه پنهان دارایی کمک می کند
نکته بعدی (پس از بهینه سازی اندازه برنامه که باعث بهبود زمان بارگیری برنامه می شود ، ذخیره سازی است. از آن استفاده کنید تا قسمت هایی از برنامه را روی مشتری نگه دارید و هر بار از بارگیری مجدد آنها جلوگیری کنید.
از نسخه های نسخه بسته و حافظه پنهان استفاده کنید
رویکرد مشترک انجام حافظه پنهان این است:
به مرورگر بگویید تا یک پرونده را برای مدت زمان طولانی (به عنوان مثال ، یک سال) ذخیره کنید:
# Server header Cache-Control: max-age=31536000
اگر آشنا نیستید که چه چیزی
Cache-Control
انجام می دهد ، به پست عالی جیک Archibald در ذخیره بهترین روشها مراجعه کنید.و هنگامی که تغییر کرده است برای مجبور کردن بارگذاری مجدد ، پرونده را تغییر نام دهید:
<!-- Before the change --> <script src="./index-v15.js"></script> <!-- After the change --> <script src="./index-v16.js"></script>
این رویکرد به مرورگر می گوید که پرونده JS را بارگیری کنید ، آن را ذخیره کرده و از نسخه ذخیره شده استفاده کنید. مرورگر فقط در صورت تغییر نام پرونده (یا اگر یک سال می گذرد) فقط به شبکه ضربه می زند.
با استفاده از وب ، همین کار را می کنید ، اما به جای شماره نسخه ، هش پرونده را مشخص می کنید. برای وارد کردن هش در نام پرونده ، از [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"
}
در ادامه مطلب
- جیک Archibald در مورد ذخیره بهترین شیوه ها
وابستگی ها و زمان اجرا را در یک پرونده جداگانه استخراج کنید
وابستگی ها
وابستگی های برنامه تمایل به تغییر کمتر از کد برنامه واقعی دارند. اگر آنها را به یک فایل جداگانه منتقل کنید ، مرورگر قادر خواهد بود آنها را به طور جداگانه ذخیره کند-و هر بار که کد برنامه تغییر می کند ، دوباره آنها را بارگیری نمی کند.
برای استخراج وابستگی ها به یک تکه جداگانه ، سه مرحله را انجام دهید:
نام پرونده خروجی را با
[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' } };
در این قطعه ، "اصلی" نام یک تکه است. این نام از مرحله 1 به جای
[name]
جایگزین می شود.در حال حاضر ، اگر برنامه را بسازید ، این بخش کل کد برنامه را شامل می شود - دقیقاً مثل این که ما این مراحل را انجام نداده ایم. اما این در یک ثانیه تغییر خواهد کرد.
در Webpack 4 ، به
optimization.splitChunks.chunks: 'all'
به پیکربندی Webpack خود اضافه کنید:// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
این گزینه تقسیم کد هوشمند را امکان پذیر می کند. با استفاده از آن ، Webpack در صورت بزرگتر شدن از 30 کیلوبایت (قبل از Minification و GZIP) کد فروشنده را استخراج می کند. همچنین کد مشترک را استخراج می کند - اگر ساخت شما چندین بسته تولید کند (به عنوان مثال اگر برنامه خود را به مسیرها تقسیم کنید ) مفید است.
در وب 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
.
پس از این تغییرات ، هر ساخت به جای یکی دو پرونده ایجاد می کند: main.[chunkhash].js
و vendors~main.[chunkhash].js
vendor.[chunkhash].js
در صورت استفاده از Webpack 4 ، اگر وابستگی های کوچک باشد ، بسته نرم افزاری فروشنده تولید نمی شود - و این خوب است:
$ 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
این اتفاق می افتد زیرا بسته نرم افزاری Webpack ، جدا از کد ماژول ها ، دارای زمان اجرا است - یک قطعه کوچک از کد که مدیریت ماژول را مدیریت می کند. هنگامی که کد را به چندین پرونده تقسیم می کنید ، این قطعه کد شامل نقشه برداری بین شناسه های قطعه و پرونده های مربوطه است:
// vendor.e6ea4504d61a1cc1c60b.js
script.src = __webpack_require__.p + chunkId + "." + {
"0": "2f2269c7f0a55a5c1871"
}[chunkId] + ".js";
Webpack شامل این زمان اجرا در آخرین تکه تولید شده است که در مورد ما vendor
است. و هر بار که هر قطعه تغییر می کند ، این قطعه کد نیز تغییر می کند و باعث می شود کل تکه vendor
تغییر کند.
برای حل این مسئله ، بیایید زمان اجرا را به یک پرونده جداگانه منتقل کنیم. در Webpack 4 ، این با فعال کردن گزینه optimization.runtimeChunk
حاصل می شود. گزینه 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
})
]
};
پس از این تغییرات ، هر ساخت و ساز سه پرونده تولید می کند:
$ 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 Docs درباره Webpack Runtime و مانیفست
- "بیشترین استفاده را از Commonschunkplugin"
- چگونه
optimization.splitChunks
وoptimization.runtimeChunk
کار runtimechunk کار
بسته بندی وب درون خطی برای ذخیره یک درخواست HTTP اضافی
برای بهتر شدن اوضاع ، سعی کنید زمان اجرای صفحه را در پاسخ 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 را با استفاده از یک منطق سرور سفارشی تولید می کنید
با صفحه وب 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> … `); });
یا با صفحه وب 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> … `); });
کد بار تنبل که الان به آن احتیاج ندارید
بعضی اوقات ، یک صفحه دارای بخش های بیشتر و کمتری است:
- اگر یک صفحه ویدیویی را در YouTube بارگذاری می کنید ، بیشتر به این فیلم اهمیت می دهید تا درباره نظرات. در اینجا ، این ویدئو مهمتر از نظرات است.
- اگر مقاله ای را در یک سایت خبری باز کنید ، بیشتر به متن مقاله اهمیت می دهید تا تبلیغات. در اینجا ، متن از تبلیغات مهمتر است.
در چنین مواردی ، عملکرد بارگذاری اولیه را با بارگیری فقط مهمترین مطالب ابتدا بهبود بخشید و بار دیگر قطعات باقی مانده را بارگیری کنید. برای این کار از عملکرد import()
و کدگذاری کد استفاده کنید:
// 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')
، این ماژول را به یک تکه جداگانه منتقل می کند:
$ 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
کوچکتر شود و زمان بارگذاری اولیه را بهبود بخشد. حتی بیشتر ، این باعث می شود که حافظه پنهان شود - اگر کد را در قسمت اصلی تغییر دهید ، Comports Chunk تحت تأثیر قرار نمی گیرد.
در ادامه مطلب
- اسناد وب برای عملکرد
import()
- پیشنهاد JavaScript برای اجرای نحو
import()
کد را به مسیرها و صفحات تقسیم کنید
اگر برنامه شما دارای چندین مسیر یا صفحات است ، اما فقط یک پرونده JS با کد (یک قطعه main
) وجود دارد ، به احتمال زیاد شما در هر درخواست بایت اضافی سرو می کنید. به عنوان مثال ، هنگامی که کاربر از صفحه اصلی سایت شما بازدید می کند:
آنها نیازی به بارگذاری کد برای ارائه مقاله ای که در صفحه دیگری وجود دارد - اما آنها آن را بارگیری می کنند. علاوه بر این ، اگر کاربر همیشه فقط از صفحه اصلی بازدید کند ، و شما در کد مقاله تغییری ایجاد می کنید ، Webpack کل بسته نرم افزاری را باطل می کند-و کاربر مجبور است مجدداً کل برنامه را بارگیری کند.
اگر برنامه را به صفحات تقسیم کنیم (یا مسیرها ، اگر یک برنامه تک صفحه ای باشد) ، کاربر فقط کد مربوطه را بارگیری می کند. به علاوه ، مرورگر کد برنامه را بهتر ذخیره می کند: اگر کد صفحه اصلی را تغییر دهید ، وب وب فقط تکه مربوطه را باطل می کند.
برای برنامه های تک صفحه ای
برای تقسیم برنامه های تک صفحه ای بر اساس مسیرها ، از import()
استفاده کنید (به بخش "کد بار تنبل که در حال حاضر نیازی به آن ندارید" مراجعه کنید). اگر از یک چارچوب استفاده می کنید ، ممکن است یک راه حل موجود برای این کار داشته باشد:
- "تقسیم کد" در اسناد
react-router
(برای واکنش) - "مسیرهای بارگیری تنبل" در اسناد
vue-router
(برای Vue.js)
برای برنامه های سنتی چند صفحه ای
برای تقسیم برنامه های سنتی بر اساس صفحات ، از نقاط ورود به وب استفاده کنید. اگر برنامه شما سه نوع صفحه دارد: صفحه اصلی ، صفحه مقاله و صفحه حساب کاربری ، - باید سه مدخل داشته باشد:
// webpack.config.js
module.exports = {
entry: {
home: './src/Home/index.js',
article: './src/Article/index.js',
profile: './src/Profile/index.js'
}
};
برای هر فایل ورودی ، صفحه وب یک درخت وابستگی جداگانه ایجاد می کند و یک بسته نرم افزاری تولید می کند که فقط ماژول هایی را شامل می شود که توسط آن ورودی استفاده می شود:
$ 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
آن را شامل نمی شوند - و کاربر هنگام مراجعه به صفحه اصلی مجبور به بارگیری این کتابخانه نخواهد بود.
درختان وابستگی جداگانه اشکال خود را دارند. اگر دو نقطه ورود از Lodash استفاده کنید ، و وابستگی های خود را به بسته نرم افزاری فروشنده منتقل نکرده اید ، هر دو نقطه ورود شامل یک نسخه از Lodash است. برای حل این مسئله ، در Webpack 4 ، optimization.splitChunks.chunks: 'all'
به پیکربندی وب خود اضافه کنید:
// webpack.config.js (for webpack 4)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
این گزینه تقسیم کد هوشمند را امکان پذیر می کند. با استفاده از این گزینه ، Webpack به طور خودکار به دنبال کد مشترک و استخراج آن در پرونده های جداگانه است.
یا در وب 3 ، از CommonsChunkPlugin
استفاده کنید - وابستگی های مشترک را به یک پرونده مشخص شده جدید منتقل می کند:
module.exports = {
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2 // 2 is the default value
})
]
};
برای یافتن بهترین مورد ، با ارزش minChunks
بازی کنید. به طور کلی ، شما می خواهید آن را کوچک نگه دارید ، اما در صورت افزایش تعداد تکه ها افزایش می یابد. به عنوان مثال ، برای 3 قطعه ، minChunks
ممکن است 2 باشند ، اما برای 30 قطعه ، ممکن است 8 باشد - زیرا اگر آن را در 2 نگه دارید ، ماژول های زیادی وارد پرونده مشترک می شوند و بیش از حد آن را باد می کنند.
در ادامه مطلب
- اسناد وب در مورد مفهوم نقاط ورود
- اسناد وب در مورد Commonschunkplugin
- "بیشترین استفاده را از Commonschunkplugin"
- چگونه
optimization.splitChunks
وoptimization.runtimeChunk
کار 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 ، مورد دوم دارای شناسه 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
اکنون به جای 4 شناسه 5 دارد
[5] ./comments.js 58 kB {0} [built]
↓ ads.js
اکنون به جای 5 شناسه 6 دارد
[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()
]
};
در ادامه مطلب
- اسناد وب در مورد hashedmoduleidsplugin
جمع بندی
- بسته نرم افزاری را ذخیره کرده و با تغییر نام بسته نرم افزاری بین نسخه ها تمایز قائل شوید
- بسته نرم افزاری را به کد برنامه ، کد فروشنده و زمان اجرا تقسیم کنید
- زمان اجرا را برای ذخیره درخواست HTTP وارد کنید
- کد غیر بحرانی بار تنبل با
import
- برای جلوگیری از بارگیری چیزهای غیر ضروری ، کد را توسط مسیرها/صفحات تقسیم کنید