共计 8144 个字符,预计需要花费 21 分钟才能阅读完成。
webpack 核心概念:
Entry: 入口
Module: 模块,webpack 中一切皆是模块
Chunk: 代码库,一个 chunk 由十多个模块组合而成,用于代码合并与分割
Loader: 模块转换器,用于把模块原内容按照需求转换成新内容
Plugin: 扩展插件,在 webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要做的事情
Output: 输出结果
webpack 流程:
webpack 启动后会从 Entry 里配置的 Module 开始递归解析 Entry 依赖的所有 Module. 每找到一个 Module, 就会根据配置的 Loader 去找出对应的转换规则,对 Module 进行转换后,再解析出当前的 Module 依赖的 Module. 这些模块会以 Entry 为单位进行分组,一个 Entry 和其所有依赖的 Module 被分到一个组也就是一个 Chunk。最好 Webpack 会把所有 Chunk 转换成文件输出。在整个流程中 Webpack 会在恰当的时机执行 Plugin 里定义的逻辑。
下面我们开始从零开始配置一个支持打包图片,CSS,LESS,SASS, 支持 ES6/ES7 和 JSX 语法,并对代码进行压缩的 webpack 配置.
1. 最简 webpack 配置
首先初始化 npm 和安装 webpack 的依赖:
npm init -y
npm install –save-dev webpack webpack-cli
配置 webpack.config.js 文件如下:
const path = require(‘path’);
module.exports = {
entry: path.resolve(__dirname, ‘src/index.js’),
output: {
path: path.resolve(__dirname, ‘dist’),
filename: ‘bundle.js’,
publicPath: ‘/’
}
}
说明: publicPath 上线时配置的是 cdn 的地址。
使用命令进行打包:
webpack –mode production
也可以将其配置到 package.json 中的 scripts 字段.
入口文件为 src/index.js, 打包输出到 dist/bundle.js.
2. 使用模板 html
html-webpack-plugin 可以指定 template 模板文件,将会在 output 目录下,生成 html 文件,并引入打包后的 js.
安装依赖:
npm install –save-dev html-webpack-plugin
在 webpack.config.js 增加 plugins 配置:
const HtmlWebpackPlugin = require(‘html-webpack-plugin’);
module.exports = {
//…other code
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, ‘src/index.html’)
})
]
}
HtmlWebpackPlugin 还有一些其它的参数, 如 title(html 的 title),minify(是否要压缩),filename(dist 中生成的 html 的文件名) 等
3. 配置 webpack-dev-server
webpack-dev-server 提供了一个简单的 Web 服务器和实时热更新的能力
安装依赖:
npm install –save-dev webpack-dev-server
在 webpack.config.js 增加 devServer 配置:
const path = require(‘path’);
const HtmlWebpackPlugin = require(‘html-webpack-plugin’);
module.exports = {
//…other code
devServer: {
contentBase: ‘./dist’,
port: ‘8080’,
host: ‘localhost’
}
}
在 package.json 的 scripts 字段中增加:
webpack-dev-server –mode development
之后,我们就可以通过 npm run dev , 来启动服务。
更多 webpack-dev-server 的知识,请访问: https://webpack.js.org/config…
4. 支持加载 css 文件
通过使用不同的 style-loader 和 css-loader, 可以将 css 文件转换成 JS 文件类型。
安装依赖:
npm install –save-dev style-loader css-loader
在 webpack.config.js 中增加 loader 的配置。
module.exports = {
//other code
module: {
rules: [
{
test: /\.css/,
use: [‘style-loader’, ‘css-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
}
]
}
}
loader 可以配置以下参数:
test: 匹配处理文件的扩展名的正则表达式
use: loader 名称
include/exclude: 手动指定必须处理的文件夹或屏蔽不需要处理的文件夹
query: 为 loader 提供额外的设置选项
如果需要给 loader 传参,那么可以使用 use+loader 的方式, 如:
module.exports = {
//other code
module: {
rules: [
{
use: [{
loader: ‘style-loader’,
options: {
insertAt: ‘top’
}
},
‘css-loader’
],
//….
}
]
}
}
5. 支持加载图片
file-loader: 解决 CSS 等文件中的引入图片路径问题
url-loader: 当图片小于 limit 的时候会把图片 Base64 编码,大于 limit 参数的时候还是使用 file-loader 进行拷贝
如果希望图片存放在单独的目录下,那么需要指定 outputPath
安装依赖:
npm install –save-dev url-loder file-loader
在 webpack.config.js 中增加 loader 的配置 (增加在 module.rules 的数组中)。
module.exports = {
//other code
module: {
rules: [
{
test: /\.(gif|jpg|png|bmp|eot|woff|woff2|ttf|svg)/,
use: [
{
loader: ‘url-loader’,
options: {
limit: 8192,
outputPath: ‘images’
}
}
]
}
]
}
}
6. 支持编译 less 和 sass
有些前端同事可能习惯于使用 less 或者是 sass 编写 css,那么也需要在 webpack 中进行配置。
安装对应的依赖:
npm install –save-dev less less-loader
npm install –save-dev node-sass sass-loader
在 webpack.config.js 中增加 loader 的配置 (module.rules 数组中)。
module.exports = {
//other code
module: {
rules: [
{
test: /\.less/,
use: [‘style-loader’, ‘css-loader’, ‘less-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
},
{
test: /\.scss/,
use: [‘style-loader’, ‘css-loader’, ‘sass-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
}
]
}
}
7. 支持转义 ES6/ES7/JSX
ES6/ES7/JSX 转义需要 Babel 的依赖,支持装饰器。
npm install –save-dev @babel/core babel-loader @babel/preset-env @babel/preset-react @babel/plugin-proposal-decorators @babel/plugin-proposal-object-rest-spread
在 webpack.config.js 中增加 loader 的配置 (module.rules 数组中)。
module.exports = {
//other code
module: {
rules: [
{
test: /\.jsx?$/,
use: [
{
loader: ‘babel-loader’,
options: {
presets: [‘@babel/preset-env’, ‘@babel/react’],
plugins: [
[require(“@babel/plugin-proposal-decorators”), {“legacy”: true}]
]
}
}
],
include: path.resolve(__dirname, ‘src’),
exclude: /node_modules/
},
]
}
}
8. 压缩 JS 文件
安装依赖:
npm install –save-dev uglifyjs-webpack-plugin
npm install –save-dev optimize-css-assets-webpack-plugin
在 webpack.config.js 中增加 optimization 的配置
const UglifyWebpackPlugin = require(‘uglifyjs-webpack-plugin’);
module.exports = {
//other code
optimization: {
minimizer: [
new UglifyWebpackPlugin({
parallel: 4
})
]
}
}
9. 分离 CSS(如果 CSS 文件较大的话)
因为 CSS 的下载和 JS 可以并行,当一个 HTML 文件很大的时候,可以把 CSS 单独提取出来加载
npm install –save-dev mini-css-extract-plugin
在 webpack.config.js 中增加 plugins 的配置, 并且将 ‘style-loader’ 修改为 {loader: MiniCssExtractPlugin.loader}。
CSS 打包在单独目录,那么配置 filename。
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’);
module.exports = {
//other code
module: {
rules: [
{
test: /\.css/,
use: [{loader: MiniCssExtractPlugin.loader}, ‘css-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
},
{
test: /\.less/,
use: [{loader: MiniCssExtractPlugin.loader}, ‘css-loader’, ‘less-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
},
{
test: /\.scss/,
use: [{loader: MiniCssExtractPlugin.loader}, ‘css-loader’, ‘sass-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: ‘css/[name].css’
})
]
}
10. 压缩 CSS 文件
安装依赖:
npm install –save-dev optimize-css-assets-webpack-plugin
在 webpack.config.js 中的 optimization 中增加配置
const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’);
module.exports = {
//other code
optimization: {
minimizer: [
new OptimizeCssAssetsWebpackPlugin()
]
}
}
11. 打包前先清空输出目录
npm install –save-dev clean-webpack-plugin
在 webpack.config.js 中增加 plugins 的配置
const CleanWebpackPlugin = require(‘clean-webpack-plugin’);
module.exports = {
//other code
plugins: [
new CleanWebpackPlugin()
]
}
至此,webpack 配置已经基本能满足需求。
完整 webpack.config.js 和 package.json 文件
webpack.config.js 文件:
const path = require(‘path’);
const htmlWebpackPlugin = require(‘html-webpack-plugin’);
const UglifyWebpackPlugin = require(‘uglifyjs-webpack-plugin’);
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’);
const CleanWebpackPlugin = require(‘clean-webpack-plugin’);
const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’);
module.exports = {
entry: path.resolve(__dirname, ‘src/index.js’),
output: {
path: path.resolve(__dirname, ‘dist’),
filename: ‘bundle.js’,
publicPath: ‘/’
},
devServer: {
contentBase: ‘./dist’,
port: ‘8080’,
host: ‘localhost’
},
module: {
rules: [
{
test: /\.jsx?$/,
use: [
{
loader: ‘babel-loader’,
options: {
presets: [‘@babel/preset-env’, ‘@babel/react’],
plugins: [
[require(“@babel/plugin-proposal-decorators”), {“legacy”: true}]
]
}
}
],
include: path.resolve(__dirname, ‘src’),
exclude: /node_modules/
},
{
test: /\.css/,
use: [{loader: MiniCssExtractPlugin.loader}, ‘css-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
},
{
test: /\.less/,
use: [{loader: MiniCssExtractPlugin.loader}, ‘css-loader’, ‘less-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
},
{
test: /\.scss/,
use: [{loader: MiniCssExtractPlugin.loader}, ‘css-loader’, ‘sass-loader’],
exclude: /node_modules/,
include: path.resolve(__dirname, ‘src’)
},
{
test: /\.(gif|jpg|png|bmp|eot|woff|woff2|ttf|svg)/,
use: [
{
loader: ‘url-loader’,
options: {
limit: 1024,
outputPath: ‘images’
}
}
]
}
]
},
optimization: {
minimizer: [
new UglifyWebpackPlugin({
parallel: 4
}),
new OptimizeCssAssetsWebpackPlugin()
]
},
plugins: [
new htmlWebpackPlugin({
template: path.resolve(__dirname, ‘src/index.html’),
}),
new MiniCssExtractPlugin({
filename: ‘css/[name].css’
}),
new CleanWebpackPlugin()
]
}
package.json 文件:
{
“name”: “webpk”,
“version”: “1.0.0”,
“description”: “”,
“main”: “webpack.config.js”,
“scripts”: {
“test”: “echo \”Error: no test specified\” && exit 1″,
“build”: “webpack –mode production”,
“dev”: “webpack-dev-server –mode development”
},
“keywords”: [],
“author”: “”,
“license”: “ISC”,
“devDependencies”: {
“@babel/core”: “^7.4.0”,
“@babel/plugin-proposal-decorators”: “^7.4.0”,
“@babel/plugin-proposal-object-rest-spread”: “^7.4.0”,
“@babel/preset-env”: “^7.4.1”,
“@babel/preset-react”: “^7.0.0”,
“babel-loader”: “^8.0.5”,
“clean-webpack-plugin”: “^2.0.1”,
“css-loader”: “^2.1.1”,
“file-loader”: “^3.0.1”,
“html-webpack-plugin”: “^3.2.0”,
“less”: “^3.9.0”,
“less-loader”: “^4.1.0”,
“mini-css-extract-plugin”: “^0.5.0”,
“node-sass”: “^4.11.0”,
“optimize-css-assets-webpack-plugin”: “^5.0.1”,
“sass-loader”: “^7.1.0”,
“style-loader”: “^0.23.1”,
“uglifyjs-webpack-plugin”: “^2.1.2”,
“url-loader”: “^1.1.2”,
“webpack”: “^4.29.6”,
“webpack-cli”: “^3.3.0”,
“webpack-dev-server”: “^3.2.1”
},
“dependencies”: {
“react”: “^16.8.4”,
“react-dom”: “^16.8.4”,
“react-redux”: “^6.0.1”,
“redux”: “^4.0.1”
}
}
更多 loader 和 plugin 的参数可以参考: https://www.webpackjs.com/loa… https://www.webpackjs.com/plu…
如果你有其它的 webpack 配置需求,欢迎留言~