در این قسمت میخوام مطلب همه چیز در مورد کار با Webpack 4 رو ادامه بدم و اطلاعات بیشتری رو در مورد Module bundling در اختیارتون قرار بدم.
در قسمت قبل بصورت خلاصه در مورد پلاگینها توضیحاتی رو دادم و تنظیمات مربوط به Production و Development مربوط به Webpack رو از هم جدا کردیم تا بتونیم در هر محیط، Pluginهای متنوع و مخصوص به خودش رو نصب کرده و بصورت بهینه از اونا استفاده کنیم.
کار با پلاگینها در محیط Production
جدا کردن CSS
یک Best practice برای محیط Production اینه که کدهای CSS رو از کدهای Javascript جدا کنید و در یک Bundle دیگه قرار بدین تا حجم Bundle اصلی کاهش پیدا کنه و این دو Bundle در کنار یکدیگر دانلود بشوند. برای اینکار از پلاگین ExtractTextWebpackPlugin استفاده میکنیم.
اگر یادتون باشه در فایل webpack.common.js یک لودر برای فایلهای scss قرار دادیم و این لودر برای محیط development به خوبی عمل میکنه. پس این لودر رو به فایل webpack.dev.js انتقال میدیم و از ExtractTextWebpackPlugin فقط برای محیط Production استفاده میکنیم.
در ابتدا باید ابزار ExtractTextWebpackPlugin رو نصب کنیم:
npm install --save-dev [email protected]
فایل webpack.common.js بصورت زیر تغییر میکنه:
... module.exports = { ... module: { rules: [ ... - { - test: /\.scss$/, - use: [ - { - loader: 'style-loader' - }, { - loader: 'css-loader' - }, { - loader: 'sass-loader' - } - ] - }, ... ] } }
فایل webpack.dev.js بصورت زیر تغییر میکنه:
const merge = require('webpack-merge') const common = require('./webpack.common.js') module.exports = merge(common, { mode: 'development', + module: { + rules: [ + { + test: /\.scss$/, + use: [ + { + loader: 'style-loader' + }, { + loader: 'css-loader' + }, { + loader: 'sass-loader' + } + ] + } + ] + } })
فایل webpack.prod.js نیز بصورت زیر تغییر میکنه:
const merge = require('webpack-merge') + const ExtractTextPlugin = require('extract-text-webpack-plugin') const common = require('./webpack.common.js') module.exports = merge(common, { mode: 'production', + module: { + rules: [ + { + test: /\.scss$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: ['css-loader', 'sass-loader'] + }) + } + ] + }, + plugins: [ + new ExtractTextPlugin('style.css') + ] })
حالا میخوایم خروجی هر 2 حالت رو با هم مقایسه کنیم. در ابتدا در حالت Development بصورت زیر هست:
> npm run develop Asset Size Chunks Chunk Names app.bundle.js 28.5 KiB app [emitted] app chat.bundle.js 1.4 KiB chat [emitted] chat
در حالت Production نیز بصورت زیر میشه:
> npm run build Asset Size Chunks Chunk Names chat.bundle.js 375 bytes 0 [emitted] chat app.bundle.js 1.82 KiB 1 [emitted] app style.css 424 bytes 1 [emitted] app
حالا که در production کدهای CSS رو از bundle کلی جدا کردیم، باید در فایل index.html به این فایل css یک لینک بدیم. بصورت زیر:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Code Splitting</title> + <link href="style.css" rel="stylesheet"> </head> <body> <script type="text/javascript" src="app.bundle.js"></script> </body> </html>
با اینکار به مرورگر این قابلیت رو میدیم که فایل CSS و Javascript رو بصورت موازی در کنار یکدیگر دانلود کنه و سرعت سایت از قبل بیشتر میشه. با اینکار اگر لود شدن Javascript هم طول بکشه، کدهای CSS در مرورگر اعمال میشن و کاربر میتونه چیزی رو در صفحه مشاهده کنه.
مدیریت و تولید HTML
هر زمان که خروجیها تغییر پیدا میکنه، ما باید کدهای درون index.html رو تغییر بدیم تا به فایلهای جدید reference بده. یک پلاگین بنام
وجود داره که این کار رو بصورت اتوماتیک برای ما انجام میده.همچنین میتونیم یک پلاگین دیگه بنام
رو اضافه کنیم تا قبل از هر build شدن، کل فایلهای درون دایرکتوری dist رو پاک کنه و فایلهای جدید رو جایگزین اونا کنه. برای نصب این 2 پلاگین بصورت زیر عمل میکنیم:npm install --save-dev html-webpack-plugin clean-webpack-plugin
حالا فایل webpack.common.js رو بصورت زیر تغییر میدیم:
const path = require('path') + const CleanWebpackPlugin = require('clean-webpack-plugin'); + const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { ... + plugins: [ + new CleanWebpackPlugin(['dist']), + new HtmlWebpackPlugin({ + title: 'My killer app' + }) + ] }
به این دلیل کدهای بالا رو درون webpack.common.js قرار دادیم چون میخواستیم اون 2 پلاگین هم در production و هم در development مورد استفاده قرار بگیرن. حالا هر بار که npm run build یا npm run develop رو اجرا کنیم، دایرکتوری dist پاک میشه و مجددا با فایلهای جدید قرار میگیره و همچنین فایل index.html هم بصورت اتوماتیک تغییر پیدا میکنه و به فایلهای مورد نظر لینک میشه.
کار با پلاگینها در محیط Development
شما میتونین در محیط Development از قدرت webpack-dev-server استفاده کنید که یک سرور ساده رو برای شما به وجود میاره و قابلیت live-reloading رو در اختیارتون قرار میده و دیگه نیاز نیس که با اعمال تغییرات، مرورگر رو رفرش کنید و این کار بصورت اتوماتیک انجام میشه. برای نصب این ابزار بصورت زیر عمل میکنیم:
npm install --save-dev webpack-dev-server
حالا فایل package.json رو بصورت زیر تغییر میدیم:
{ ... "scripts": { - "develop": "webpack --watch --config webpack.dev.js", + "develop": "webpack-dev-server --config webpack.dev.js", } ... }
میبینید که به جای webpack از webpack-dev-server استفاده کردیم. حالا اگر دستور npm run build رو مجددا اجرا کنیم، خروجی بصورت زیر خواهد بود:
> npm run develop 「wds」: Project is running at http://localhost:8080/ 「wds」: webpack output is served from /
حالا آدرس
رو در مرورگر باز کنید و یک تغییر رو در کدهای Javascript یا CSS به وجود بیارید. همونطور که خواهید دید webpack دوباره bundle خروجی رو میسازه و مرورگر نیز بصورت اتوماتیک رفرش میشه و آخرین تغییرات رو نمایش میده.HotModuleReplacement
پلاگین HotModuleReplacement یک قدم فراتر از love reloading جلو رفته و در زمان اجرای برنامه ماژولهایی که تغییر کردند رو بدون رفرش شدن کل صفحه جایگزین میکنه و خروجی رو نمایش میده. اگر به درستی از این ابزار استفاده کنید مدت زمان زیادی در زمان توسعه و Development رو مخصوصا در Single page applicationها برای شما ذخیره میکنه و نیاز نیست که با هر تغییر کوچک منتظر بمونین تا کل پروژه دوباره build بشه و بتونین تغییرات اون رو مشاهده کنید.
با اینکار همه حالات و state هایی که در مرورگر ایجاد کردید سر جاش باقی میمونه و فقط اون چیزایی که تغییر پیدا کرده، بروز رسانی میشه و میتونیم خروجی رو فورا در مرورگر مشاهده کنیم.
برای اینکار فایل webpack.dev.js رو بصورت زیر تغییر میدیم:
+ const webpack = require('webpack') const merge = require('webpack-merge') const common = require('./webpack.common.js') module.exports = merge(common, { mode: 'development', + devServer: { + hot: true + }, + plugins: [ + new webpack.HotModuleReplacementPlugin() + ], ... }
فایل index.js رو نیز بصورت زیر تغییر میدیم:
+ if (module.hot) { + module.hot.accept() + } ...
با اینکار ویژگی hot-module-replacement رو قبول میکنیم و بهش اجازه میدیم. مجددا دستور npm run develop رو اجرا کنید و کارهای زیر رو انجام بدین:
- بر روی Open chat کلیک کنید
- حالا یک آیتم به فایل people.js اضافه کنید
- مجددا بر روی Open chat کلیک کنید
خروجی بصورت زیر میشه:
این کارها در پس زمینه انجام میشه:
- زمانی که بر روی Open chat کلیک میشه، ماژول chat دریافت و initialize میشه
- HotModuleReplacement یا HMR متوجه تغییرات در ماژول people.js میشه
- module.hot.accept اجازه میده که این تغییرات در خروجی مورد استفاده قرار بگیره
- زمانی که Open chat مجددا کلیک میشه، کدهای مربوط به ماژول update شده رو اجرا میکنه و باعث میشه که عدد 4 رو نمایش بده.
CSS Replacement
حالا میخوام رنگ دکمه در کدهای scss رو تغییر بدم و ببینم که چه اتفاقی میوفته. برای اینکار بصورت زیر عمل میکنم:
button { ... - background: #24b47e; + background: red; ... }
با ذخیره کردن این تغییرات بدون اینکه صفحه رفرش بشه و وضعیت محتوای درون مرورگر تغییر پیدا کنه، رنگ دکمهها قرمز میشن:
Hot module replacement یکی از پیشرفتهترین و مدرنترین روشها برای تست کردن برنامهها در محیط Development میباشد و بهتره که شما نیز در پروژههاتون از اون استفاده کنید.
نتیجهگیری
سعی شد در این 4 قسمت توضیحات مقدماتی در مورد همه جنبههای Webpack در اختیارتون قرار بگیره تا با قدرت این ابزار آشنا بشید و اگر تا حالا کار با اون رو شروع نکردید، بتونین از اون استفاده کنید. شاید مدت زمانی طول بکشه تا کار با Webpack و تنظیمات اون رو به خوبی یاد بگیرید ولی ارزش یادگیری داره و خیلی بهتون کمک خواهد کرد.
شما میتونین برای مطاالعه بیشتر مستندات Webpack رو مطالعه کنید.
اولین دیدگاه این پست رو تو بنویس !