1, webpack手动搭建15步
1,安装
npm install -g webpack webpack-cli
2, 打包编译HTML文件
npm install -D clean-webpack-plugin 清除dist文件
npm install -D html-webpack-plugin 生成index.html
3, 热更新
npm install -D webpack-dev-server
4,babel编译
npm install babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
npm install -S @babel/runtime
npm install -S @babel/plugin-syntax-dynamic-import
5, CSS 处理
npm install -D css-loader style-loader
sass npm install -D node-sass sass-loader
less npm install -D less less-loader
postcss: 自动添加前缀,css模块化
npm install -D postcss-loader
npm install -D autoprefixer
6, 启用模块热替换
hot:true
安装 cross-env 添加一个环境变量,
cnpm install cross-env -S
环境分离,需要安装webpack-merge
cnpm install webpack-merge -D
7, 环境变量
通过webpack.DefinePlugin 插件获取变量的值
8, 开发环境配置查看源码
devtool:'cheap-module-eval-source-map'
9, css提取
cnpm install -D mini-css-extract-plugin
10, 图片字体资源处理
cnpm install -D file-loader url-loader
在最外层index.html文件中引入图片的,需要添加插件html-witming-loader
cnpm install -D html-withimg-loader
编译之后:图片路径是相对路径,打包之后就会有问题
11, 提取公共代码
配置:optimization中的 splitChunks
12, JS 和 CSS压缩
cnpm install -D babili-webpack-plugin
cnpm install -D optimize-css-assets-webpack-plugin
13, 静态资源的相对路径改为绝对路径
cnpm install -D copy-webpack-plugin
css-loader开始模块化
14, Mock
cnpm install -D mockjs
cnpm install -D express
cnpm install -D nodemon
2, 完整的webpack手动构建代码
1,webpack.base.config
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ENV_NODE = process.env.ENV_NODE
console.log(process.env.MOCK)
module.exports = {
entry: {
index: './src/index.js',
about: './src/about.js',
},
output: {
filename: ENV_NODE === 'production' ? '[name].[contenthash:7].js' : '[name].[hash:7].js',
chunkFilename: ENV_NODE === 'production' ? '[name].[chunkhash:7].js' : '[name].[hash:7].js',
path: path.resolve(__dirname, "dist"),
publicPath: '/',
},
resolve: {
alias: { // 配置别名
'@': path.resolve(__dirname, 'src'),
},
extensions: ['.js', '.css', '.scss', '.less']
},
module: {
rules: [
{
test: /\.(jsx|js)$/,
use: {
loader: "babel-loader",
},
exclude: /node_modules/,
},
{
test: /\.(css|scss|sass)$/,
use: [ // MiniCssExtractPlgin.loader替换 style-loader 为了提取CSS
ENV_NODE === 'production' ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options:{
modules: {
localIdentName: '[path][name]-[local]-[hash:base64:5]'
}
}
},
'postcss-loader',
'sass-loader'
]
},
{
test: /\.less$/,
use: [
ENV_NODE === 'production' ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options:{
modules:{
localIdentName: '[path][name]-[local]-[hash:base64:5]'
}
}
},
'postcss-loader',
'less-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 1024 * 10, // 10k以内的图片转Base64打包到js中
name: '[name].[hash:7].[ext]', // 打包的文件名
outputPath: 'images/',
esModule: false
}
}]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use:[{
loader: 'url-loader',
options: {
limit: 1024 * 5, // 10k以内的打包到js中
name: '[name].[hash:7].[ext]',
outputPath: 'font/'
}
}]
},
{
test: /\.(htm|html)$/,
use: [{
loader: 'html-withimg-loader',
}]
}
],
},
plugins: [
new CleanWebpackPlugin(), // 清理dist 文件夹
new HtmlWebpackPlugin({
// 自动生成html
template: "./index.html", //
filename: "index.html",
// script 标签位于哪里,默认true,在body里面, 还有head, false
inject: true,
hash: true, // 今天
minify: {
minifyJS: true,
minifyCSS: true,
removeComments: true,
removeEmptyAttributes: true,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
},
chunks: ['styles', 'vendor', 'common', 'manifest', 'index'],
}),
new HtmlWebpackPlugin({
// 自动生成html
template: "./about.html", //
filename: "about.html",
// script 标签位于哪里,默认true,在body里面, 还有head, false
inject: true,
hash: true, // 今天
minify: {
minifyJS: true,
minifyCSS: true,
removeComments: true,
removeEmptyAttributes: true,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
},
chunks: ['styles', 'vendor', 'common', 'manifest', 'about'],
}),
new CopyWebpackPlugin({
patterns: [
{ from: path.join(__dirname, '/src/public'), to: 'public' }
]
})
],
// 提取公共代码
optimization: {
splitChunks: {
chunks: 'all', // 表示从哪些chunks里面抽取代码 initial(入口文件), all(所有), async(异步模块, 默认)
minSize: 30000, // 限制抽取出来的文件在压缩前的最小大小:默认30000
maxSize: 0, // 0表示不限制最大值 默认是0
minChunks: 1, // 表示被引入次数, 默认是1
maxAsyncRequests: 5, // 最大异步请求数 默认是5
maxInitialRequests: 3, // 最大的初始化加载次数 默认3
automaticNameDelimiter: '~', // 抽取出来的文件的自动生成名字的分隔符, 默认~
name: true, // 抽取出来文件的名字,true表示自动生成文件名字, 默认true
// 上面的那么多参数,都是默认值,可以不用管,
// cachGroups 才是我们配置的关键,它可以继承、覆盖上面splitChunks中所有的参数值,
// 设置缓存组件用来抽取满足不同规则的chunk
cacheGroups: {
// 将所有的css文件打包为一个,将权重设置为最高
sytles: {
name: 'styles',
test: /\.(css|scss|sass|less)$/,
chunks: 'all',
enforce: true, // 使用上层的配置minSize配置
priority: 20, // 优先级, 越大越高
},
// 第三方库单独打包
vendor: {
test: /node_modules/,
chunks: 'initial',
name:'vendor',
priority: 10,
enforce:true
},
// 把所有引入超过1次的模块抽取为common
common: {
name: 'common',
chunks: 'initial',
priority: 2,
minChunks: 2,
enforce:true
}
}
},
runtimeChunk: { // 提取manifest, 管理模块之间的交互
name: 'manifest'
}
}
};
2,webpack.dev.config
const { merge } = require('webpack-merge')
const path = require('path')
const baseConfig = require('./webpack.base.config')
const webpack = require("webpack");
// const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devConfig = {
mode: "development",
devServer: {
contentBase: path.join(__dirname, 'dist'), // 网站根目录
host: "localhost",
port: "9527",
compress: true, // 设置服务端压缩
hot: true // 开启模块热替换
},
devtool: 'cheap-module-eval-source-map',
plugins: [
new webpack.NamedModulesPlugin(), // 当开启HMR的时候,使用该插件会显示模块的相对路径,
new webpack.HotModuleReplacementPlugin(), // 开启HMR
new webpack.DefinePlugin({ // 通过插件获取打包的环境变量
"ENV_MOCK": process.env.MOCK
}),
// 提取CSS
// new MiniCssExtractPlugin({
// filename: 'css/[name].[hash:7].css',
// chunkFilename: 'css/[id].[name].[hash:7].css'
// })
],
};
module.exports = merge(baseConfig, devConfig)
3, webpack.prod.config.js
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.base.config')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const BabiliPlugin = require('babili-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const proConfig = {
mode: 'production',
plugins: [
// 提取CSS
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:7].css',
chunkFilename: 'css/[name].[chunkhash:7].css'
})
],
optimization:{
minimizer: [
new BabiliPlugin(), // 基于Babel的压缩工具, 支持ES6的一些特性, 取代UglifyJS
new OptimizeCSSAssetsPlugin() // 压缩CSS
]
}
}
module.exports = merge(baseConfig, proConfig)
3, webpack总结
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程
- 初始化参数: 从配置文件 和命令行中读取与合并参数,初始化本次构建的配置参数,得出最终的参数;
- 开始编译: 用上一步得到的参数初始化
Compiler对象,加载配置文件的所有plugin,执行对象的 run 方法开始执行编译; - 确定入口: 根据配置中的
entry找出所有的入口文件,递归遍历所有的入口文件; - 编译模块: 从入口文件出发,调用所有配置的
loader对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。 - 输出资源: 所有文件的编译及转化都已经完成,也就是最终输出的资源,其中包括即将输出的资源、代码块
Chunk等等信息。
总结:用一句话概括本质:
webpack是一个打包模块化js的工具,可以通过loader转换文件,通过plugin扩展功能。