本文将通过介绍webpack的核心模块,让开发人员具备搭建脚手架的底层基础能力,并能快速上手。首先通过一张图看懂webpack的构建流程以及需要具备的核心知识点。
1、准备
在控制台中输入以下代码,创建示例工程
//创建项目根目录
mkdir demo-cli && cd demo-cli
//初始化项目
npm init
一路确认,直到完成。再安装两个核心插件:
1、webpack核心包
npm i webpack -D
2、webpack-cli包
npm i webpack-cli -D
新建src和public文件夹,分别用于存放源代码和静态资源,并初始化创建src/index.js和public/index.html文件。完成后项目结构如下:
2、环境定义
webpack对环境有明确的定义,可通过mode参数配置:
- development:代表开发环境,当配置为该值时,webpack需配合webpack-dev-server插件使用,在本地启动服务器,用于开发和调试代码。
- production:代表生产环境,当配置为该值时,webpack会对所有的html和js进行编译构建,并输出到指定的路径,用于发布到生产环境。
项目根目录新建build文件夹,用于存放webpack构建脚本。新建如下文件:
- webpack.dev.js:开发环境配置
- webpack.prod.js:生产环境配置
- webpack.base.js:公共配置
完成本步骤后项目结构如下:
3、配置入口和出口
webpack通过entry配置,找到入口文件,开始解析文件并构建AST语法树,找到依赖,并递归下去,经过一系列编译后通过output配置,输出到指定路径下。
在webpack.base.js中配置如下:
const path = require('path')
module.exports = {
//入口配置
entry: {
//入口文件
'index': './src/index.js'
},
//出口配置
output: {
//编译后的文件输出目标路径
path: path.resolve(__dirname, '../dist'),
//编译后的输出文件名
filename: '[name].[hash].js',
//在dist中输出的html文件中引入的css和js文件路径前面那串字符串
publicPath: ''
}
}
安装html-webpack-plugin插件,该插件用于生成html文件,并在body中通过script标签引入所有webpack构建后的bundle。如果使用了样式抽离插件(mini-css-extract-pulugin),样式文件也会通过link标签在html中引入。
npm i html-webpack-plugin -D
并在webpack.base.js中追加以下配置
...
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
...
//插件配置
plugins: [
//生成一个html文件,并在该文件中通过script标签引入所有webpack构建后的bundle
//如果使用了mini-css-extract-plugin抽离样式文件,也会在该文件中通过link标签引入css文件
new HtmlWebpackPlugin({
//html模板文件位置
template: './public/index.html',
//生成的html文件名
filename: 'index.html',
//生成的index.html引用的文件,这里设置的是entry中的key
chunks: ['index']
})
]
}
因为区分了webpack.dev.js和webpack.prod.js分别配置开发环境和生产环境的构建脚本,因此需要安装webpack-merge插件,该插件用于合并配置脚本。
npm i webpack-merge -D
- webpack.dev.js 改造如下:
const path = require('path')
const base = require('../build/webpack.base.js')
const { merge } = require('webpack-merge')
module.exports = merge(base, {
//定义环境
mode: 'development',
//定义开发服务
devServer: {
//本地静态资源文件文件夹,用来配置该文件夹内的静态资源支持http访问
static: [
//本地public路径
path.resolve(__dirname, './public'),
//构建目标路径
path.resolve(__dirname, './dist')
],
//本地启动服务后的访问IP
host: 'localhost',
//本地启动服务后的访问端口
port: 8080,
//服务启动后自动打开浏览器
open: true,
}
})
然后在package.json文件中配置启动命令。
“serve”: "webpack serve --config webpack build/webpack.dev.js --color --progress --hot"
安装webpack-dev-serve用于启动本地服务
npm i webpack-dev-server -D
配置并安装完相关插件后,可以在控制台尝试启动本地服务
npm run serve
浏览器自动打开,并在控制台输出打印日志,则说明开发环境配置正常。
- webpack.prod.js 改造如下:
const path = require('path')
const base = require('../build/webpack.base.js')
const { merge } = require('webpack-merge')
module.exports = merge(base, {
//定义环境
mode: 'production'
})
然后在package.json文件中配置生产命令
"build": "webpack --config build/webpack.prod.js --color --progress"
尝试在控制台执行构建命令
npm run build
构建完成后,在dist目录下生成了js和html文件,则说明生产构建成功。
4、样式处理
我们通过以下loader来处理样式:
- style-loader:通过js脚本创建style标签,里面包含一些样式
- css-loader:识别css文件,通过特定语法识别并导出内容,导出内容格式为数组,页面并不能直接使用
- postcss-loader:处理样式浏览器兼容性,自动补全样式前缀,
- sass-loader:编译解析scss样式
npm i style-loader css-loader postcss-loader sass-loader sass -D
定义postcss的配置文件,这里需要依赖postcss,postcss-preset-env,cssnano插件
npm i postcss postcss-preset-env cssnano -D
然后定义postcss.config.js文件,并配置如下:
module.exports = {
plugins: {
'postcss-preset-env': {},//处理兼容性
'cssnano': {} //压缩样式
}
}
修改index.html页面,增加样式代码案例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>webpack脚手架基础构建能力</title>
</head>
<body>
<div>我是index.html</div>
<div class="item-box">
<div class="item">我是item一</div>
<div class="item">我是item二</div>
</div>
</body>
</html>
创建scss文件,内容如下:
// src/css/main.scss.item-box{
display:flex;
justify-content: center;
align-items: center;
.item{
color: #ffffff;
width: 100px;
height: 100px;
background-color: #00a0e4;
}
}
然后在index.js中通过import引入scss文件
- webpack.dev.js改造 ,追加loader解析命令
...
module.exports = merge(base, {
...
//配置loader规则
module: {
rules: [
//编译本地css文件
{
test: /.css$/,
use: [
{loader: 'style-loader'},
{loader: 'css-loader'},
{loader: 'postcss-loader'}
]
},
//编译本地scss文件
{
test: /.scss$/,
use: [
{loader: 'style-loader'},
{loader: 'css-loader'},
{loader: 'postcss-loader'},
{loader: 'sass-loader'}
]
}
]
}
})
尝试启动项目
npm run serve
可以通过浏览器控制台查看css样式是否补全了前缀,以此验证loader是否处理成功。
生产环境和开发环境对样式的处理是不一样的,开发环境webpack是启动的本地服务器,可将样式内联在js中,但生产环境一般需要抽离成单独的css文件,以避免单个js文件过大,影响加载性能。因此需要用到mini-css-extract-plugin插件来抽离样式文件
npm i mini-css-extract-plugin -D
- webpack.prod.js 改造,追加以下配置:
...
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = merge(base, {
...
//配置loader规则
module: {
rules: [
//编译本地css文件
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
{loader: 'css-loader'},
{loader: 'postcss-loader'}
]
},
//编译本地scss文件
{
test: /.scss$/,
use: [
MiniCssExtractPlugin.loader,
{loader: 'css-loader'},
{loader: 'postcss-loader'},
{loader: 'sass-loader'}
]
}
]
},
plugins: [
//配置样式抽离插件,生成的css文件名为[name],[name]为entry中定义的key
new MiniCssExtractPlugin({
filename: "[name].[hash].css"
})
]
})
然后我们运行
npm run build
查看生成的dist文件夹是否生成了css文件,并在html中通过link外部引用。
细心的小伙伴会发现,每次构建build命令,dist目录会有很多历史文件,这时需要用到clean-webpack-plugin插件,用于清除dist目录的文件
npm i clean-webpack-plugin -D
在webpack.prod.js中追加如下内容
...
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = merge(base, {
...
plugins: [
...
//配置清除dist目录的插件
new CleanWebpackPlugin()
]
})
然后我们运行
npm run build
dist目录下只保留了最新生成的文件。
到这里,我们已初步完成脚手架核心能力搭建
在下一节,我们将继续完善脚手架底层能力:
- js编译与解析
- 文件处理
- source-map的处理
- 路径解析处理