ওয়েবপ্যাক কীভাবে অ্যাসেট ক্যাশিংয়ে সাহায্য করে
অ্যাপের সাইজ অপ্টিমাইজ করার পর যে বিষয়টি অ্যাপ লোডিং টাইম উন্নত করে, তা হলো ক্যাশিং। অ্যাপের কিছু অংশ ক্লায়েন্টে রাখতে এবং প্রতিবার সেগুলো পুনরায় ডাউনলোড করা এড়াতে এটি ব্যবহার করুন।
বান্ডেল ভার্সনিং এবং ক্যাশে হেডার ব্যবহার করুন
ক্যাশিং করার প্রচলিত পদ্ধতিটি হলো:
ব্রাউজারকে একটি ফাইল খুব দীর্ঘ সময়ের জন্য (যেমন, এক বছর) ক্যাশ করে রাখতে বলুন:
# Server header Cache-Control: max-age=31536000Cache-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]এর জায়গায় এই নামটি প্রতিস্থাপিত হবে।এখন পর্যন্ত, আপনি যদি অ্যাপটি বিল্ড করেন, তাহলে এই অংশে সম্পূর্ণ অ্যাপ কোডটি অন্তর্ভুক্ত থাকবে – যেন আমরা এই ধাপগুলো সম্পন্নই করিনি। কিন্তু একটু পরেই এটি বদলে যাবে।
webpack 4-এ , আপনার webpack কনফিগ-এ
optimization.splitChunks.chunks: 'all'অপশনটি যোগ করুন:// webpack.config.js (for webpack 4) module.exports = { optimization: { splitChunks: { chunks: 'all' } } };এই অপশনটি স্মার্ট কোড স্প্লিটিং সক্ষম করে। এর মাধ্যমে, ওয়েবপ্যাক ভেন্ডর কোড এক্সট্র্যাক্ট করবে যদি এর সাইজ ৩০ কিলোবাইটের বেশি হয়ে যায় (মিনিফিকেশন এবং জিজিপ করার আগে)। এটি কমন কোডও এক্সট্র্যাক্ট করবে – যা তখন কাজে আসে যখন আপনার বিল্ড একাধিক বান্ডেল তৈরি করে (যেমন, যদি আপনি আপনার অ্যাপকে বিভিন্ন রাউটে ভাগ করেন )।
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নামের একটি আলাদা ফাইলে স্থানান্তর করে।
এই পরিবর্তনগুলির পরে, প্রতিটি বিল্ড একটির পরিবর্তে দুটি ফাইল তৈরি করবে: main.[chunkhash].js এবং vendor.[chunkhash].js (webpack 4-এর জন্য vendors~main.[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
ব্রাউজারটি এই ফাইলগুলোকে আলাদাভাবে ক্যাশ করে রাখত – এবং শুধু পরিবর্তিত কোডটুকুই পুনরায় ডাউনলোড করত।
ওয়েবপ্যাক রানটাইম কোড
দুর্ভাগ্যবশত, শুধু ভেন্ডর কোড বের করাই যথেষ্ট নয়। যদি আপনি অ্যাপ কোডে কিছু পরিবর্তন করার চেষ্টা করেন:
// 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";
ওয়েবপ্যাক এই রানটাইমটিকে সর্বশেষ জেনারেট হওয়া চাঙ্কে অন্তর্ভুক্ত করে, যা আমাদের ক্ষেত্রে vendor '। এবং যখনই কোনো চাঙ্ক পরিবর্তিত হয়, কোডের এই অংশটিও পরিবর্তিত হয়ে যায়, যার ফলে পুরো vendor চাঙ্কটি পরিবর্তিত হয়ে যায়।
এর সমাধান করতে, রানটাইমটিকে একটি আলাদা ফাইলে সরিয়ে নেওয়া যাক। ওয়েবপ্যাক ৪-এ, 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
})
]
};
এই পরিবর্তনগুলোর পর, প্রতিটি বিল্ড তিনটি ফাইল তৈরি করবে:
$ 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>
আরও পড়ুন
- দীর্ঘমেয়াদী ক্যাশিং বিষয়ে ওয়েবপ্যাক গাইড
- ওয়েবপ্যাক রানটাইম এবং ম্যানিফেস্ট সম্পর্কে ওয়েবপ্যাক ডক্স
- CommonsChunkPlugin থেকে সর্বাধিক সুবিধা লাভ করা
-
optimization.splitChunksএবংoptimization.runtimeChunkকীভাবে কাজ করে
অতিরিক্ত HTTP অনুরোধ বাঁচাতে ওয়েবপ্যাক রানটাইম ইনলাইন করুন
বিষয়টিকে আরও ভালো করার জন্য, ওয়েবপ্যাক রানটাইমকে এইচটিএমএল রেসপন্সের মধ্যে ইনলাইন করার চেষ্টা করুন। অর্থাৎ, এর পরিবর্তে:
<!-- 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 এর ক্ষেত্রে ততটা গুরুত্বপূর্ণ না হলেও এর প্রভাব থাকতে পারে)।
এইভাবে এটি করতে হয়।
আপনি যদি HtmlWebpackPlugin দিয়ে HTML তৈরি করেন
আপনি যদি 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 তৈরি করেন
ওয়েবপ্যাক ৪ দিয়ে:
রানটাইম চাঙ্কের তৈরি হওয়া নামটি জানতে
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> … `); });
অথবা ওয়েবপ্যাক ৩ দিয়ে:
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> … `); });
যে কোড আপনার এই মুহূর্তে প্রয়োজন নেই, তা লেজি-লোড করুন।
কখনও কখনও, একটি পৃষ্ঠার কমবেশি গুরুত্বপূর্ণ অংশ থাকে:
- আপনি যখন ইউটিউবে কোনো ভিডিও পেজ খোলেন, তখন মন্তব্যের চেয়ে ভিডিওটি নিয়েই বেশি ভাবেন। এখানে, মন্তব্যের চেয়ে ভিডিওটিই বেশি গুরুত্বপূর্ণ।
- আপনি যখন কোনো সংবাদ সাইটে একটি নিবন্ধ খোলেন, তখন বিজ্ঞাপনের চেয়ে নিবন্ধটির লেখার প্রতিই বেশি মনোযোগ দেন। এখানে, বিজ্ঞাপনের চেয়ে লেখাটিই বেশি গুরুত্বপূর্ণ।
এই ধরনের ক্ষেত্রে, প্রথমে শুধু সবচেয়ে গুরুত্বপূর্ণ অংশগুলো ডাউনলোড করে এবং পরে বাকি অংশগুলো লেজি লোড করে প্রাথমিক লোডিং পারফরম্যান্স উন্নত করুন। এর জন্য 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 বান্ডেলটি ছোট হবে, যা প্রাথমিক লোডিং সময়কে উন্নত করবে। শুধু তাই নয়, এটি ক্যাশিংকেও উন্নত করবে – আপনি যদি মূল চাঙ্কে কোড পরিবর্তন করেন, তবে কমেন্টস চাঙ্ক প্রভাবিত হবে না।
আরও পড়ুন
-
import()ফাংশনের জন্য ওয়েবপ্যাক ডক্স -
import()সিনট্যাক্স বাস্তবায়নের জন্য জাভাস্ক্রিপ্ট প্রস্তাবনা
কোডটিকে রাউট এবং পেজে ভাগ করুন
যদি আপনার অ্যাপে একাধিক রাউট বা পেজ থাকে, কিন্তু কোডসহ একটিমাত্র JS ফাইল (একটি একক main অংশ) থাকে, তাহলে সম্ভবত আপনি প্রতিটি অনুরোধে অতিরিক্ত বাইট পরিবেশন করছেন। উদাহরণস্বরূপ, যখন একজন ব্যবহারকারী আপনার সাইটের হোম পেজ ভিজিট করেন:

অন্য পৃষ্ঠায় থাকা কোনো আর্টিকেল রেন্ডার করার জন্য তাদের কোড লোড করার প্রয়োজন নেই – কিন্তু তারা তা লোড করবেই। অধিকন্তু, যদি ব্যবহারকারী সবসময় শুধু হোম পেজ ভিজিট করেন এবং আপনি আর্টিকেলের কোডে কোনো পরিবর্তন করেন, তাহলে ওয়েবপ্যাক পুরো বান্ডেলটিকে অবৈধ করে দেবে – এবং ব্যবহারকারীকে পুরো অ্যাপটি পুনরায় ডাউনলোড করতে হবে।
যদি আমরা অ্যাপটিকে পেজে (অথবা রাউটে, যদি এটি একটি সিঙ্গেল-পেজ অ্যাপ হয়) ভাগ করি, তাহলে ব্যবহারকারী শুধুমাত্র প্রাসঙ্গিক কোডটিই ডাউনলোড করবে। এছাড়াও, ব্রাউজার অ্যাপের কোড আরও ভালোভাবে ক্যাশ করবে: আপনি যদি হোম পেজের কোড পরিবর্তন করেন, ওয়েবপ্যাক শুধুমাত্র সংশ্লিষ্ট অংশটিকেই বাতিল করবে।
একক পৃষ্ঠার অ্যাপের জন্য
রাউট অনুযায়ী সিঙ্গেল-পেজ অ্যাপ ভাগ করতে import() ব্যবহার করুন (দেখুন “লেজি-লোড কোড যা আপনার এখন প্রয়োজন নেই” অংশটি)। আপনি যদি কোনো ফ্রেমওয়ার্ক ব্যবহার করেন, তবে এর জন্য সেখানে একটি বিদ্যমান সমাধান থাকতে পারে:
-
react-routerএর ডক্স-এ "কোড স্প্লিটিং" (React-এর জন্য) -
vue-routerএর ডক্স-এ "Lazy Loading Routes" (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
সুতরাং, যদি শুধুমাত্র আর্টিকেল পেজটি লোডাশ ব্যবহার করে, তাহলে home এবং profile বান্ডেলগুলোতে এটি অন্তর্ভুক্ত থাকবে না – এবং হোম পেজে যাওয়ার সময় ব্যবহারকারীকে এই লাইব্রেরিটি ডাউনলোড করতে হবে না।
তবে আলাদা ডিপেন্ডেন্সি ট্রি-এর কিছু অসুবিধাও আছে। যদি দুটি এন্ট্রি পয়েন্ট লোডাশ (Lodash) ব্যবহার করে, এবং আপনি আপনার ডিপেন্ডেন্সিগুলোকে কোনো ভেন্ডর বান্ডেলে (vendor bundle) স্থানান্তর না করে থাকেন, তাহলে উভয় এন্ট্রি পয়েন্টেই লোডাশের একটি কপি অন্তর্ভুক্ত থাকবে। এর সমাধান করতে, ওয়েবপ্যাক ৪-এ (webpack 4), আপনার ওয়েবপ্যাক কনফিগ-এ (webpack config) 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 এর মান নিয়ে পরীক্ষা-নিরীক্ষা করতে পারেন। সাধারণত, এর মান কম রাখাই ভালো, কিন্তু চাঙ্কের সংখ্যা বাড়লে এটিও বাড়াতে হবে। উদাহরণস্বরূপ, ৩টি চাঙ্কের জন্য minChunks মান ২ হতে পারে, কিন্তু ৩০টি চাঙ্কের জন্য তা ৮ হতে পারে – কারণ এর মান ২ রাখলে কমন ফাইলে অনেক বেশি মডিউল ঢুকে যাবে, যা ফাইলটিকে অতিরিক্ত স্ফীত করে তুলবে।
আরও পড়ুন
- এন্ট্রি পয়েন্টের ধারণা সম্পর্কে ওয়েবপ্যাক ডক্স
- CommonsChunkPlugin সম্পর্কে Webpack ডকুমেন্টেশন
- 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
ডিফল্টভাবে, একটি কাউন্টার ব্যবহার করে আইডি গণনা করা হয় (অর্থাৎ প্রথম মডিউলের আইডি ০, দ্বিতীয়টির আইডি ১, এবং এভাবেই চলতে থাকে)। এতে সমস্যা হলো, যখন আপনি একটি নতুন মডিউল যোগ করেন, তখন সেটি মডিউল তালিকার মাঝখানে চলে আসতে পারে, যার ফলে পরবর্তী সমস্ত মডিউলের আইডি পরিবর্তন হয়ে যায়।
$ 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] ./comments.js 58 kB {0} [built]
↓ ads.js আইডি এখন ৫-এর পরিবর্তে ৬ হবে।
[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 সম্পর্কে Webpack ডক্স
সারসংক্ষেপ
- বান্ডেলটি ক্যাশ করুন এবং বান্ডেলের নাম পরিবর্তন করে সংস্করণগুলোর মধ্যে পার্থক্য করুন।
- বান্ডেলটিকে অ্যাপ কোড, ভেন্ডর কোড এবং রানটাইমে বিভক্ত করুন
- HTTP অনুরোধ সংরক্ষণ করতে রানটাইম ইনলাইন করুন
-
importমাধ্যমে অ-গুরুত্বপূর্ণ কোড লেজি-লোড করুন - অপ্রয়োজনীয় জিনিস লোড হওয়া এড়াতে রাউট/পেজ অনুযায়ী কোড ভাগ করুন।