模块支持方案
webpack 支持 CommonJS(配置文件是 Node 环境下运行的),AMD,ES6 Module 规范。
核心概念
从 entry 进入项目,经过 loader、plugin 打包,之后输出 output
entry、output
entry可以是单个字符串,也可以是一个字符串数组(多入口),一般写成对象格式。 key表示名字,value表示入口文件。
详细可以参考官方文档。
module.exports = {
// entry: 'xxx',
// entry: ['a', 'b'],
entry: {
app: "./app.js",
app2: "./app2.js",
},
};
output就是输出的结果文件。官方文档。
const path = require("path");
module.exports = {
entry: {
app: "./app.js",
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].[hash:6].[id].[chunkhash].bundle.js", // name对应上面enrty的key
},
};
loader
是webpack的编译方法,webpack自身只能处理JavaScript,所以需要依赖loader来处理别的类型的资源文件。
webpack只能负责打包,相关的编译工作也需要依赖loader处理。 loader本质上只是一个方法,使用时基本需要额外安装。
使用时,在rules数组中使用,loader的执行顺序符合从右往左(从下到上、从数组的最后执行到第一个,compose)
module.exports = {
module: {
rules: [
{
test: /\.css$/, // 用正则匹配什么类型的文件
use: [
{ loader: "style-loader" }, // 用什么loader处理
{
loader: "css-loader",
options: {
// loader的配置项
modules: true,
},
},
{ loader: "sass-loader" },
],
},
],
},
};
常见的 loader
css-loader,style-loader等处理css的loaderurl-loader,image-loader等图片文字文件等资源处理的loaderless-loader,sass-loader,babel-loader等编译loadervue-loader等语法糖loader
plugin
plugin是webpack的额外扩展:
- 一些插件式的额外功能由
plugin定义,帮助webpack优化代码,提供功能。 plugin也有一些是webpack自带的,也有需要额外安装的。
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack"); // 访问内置的插件
const path = require("path");
module.exports = {
entry: "./path/to/my/entry/file.js",
output: {
filename: "my-first-webpack.bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
},
],
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({ template: "./src/index.html" }),
],
};
常见的 plugin
commonsChunkPlugin,uglifyjsWebpackPlugin,PurifyCss等优化文件体积的插件
HtmlWebpackPlugin,HotModuleReplacementPlugin等
编译 ES6
需要安装的 loader
npm install babel-loader @babel/core --save-dev
Babel-preset
presets 是存储 JavaScript 不同标准的插件,通过正确使用 presets,来告诉 babel 按照哪个规范编译。 常见规范:
- es2015
- es2016
- es2017
- env(通常采用,包括上面的三个和浏览器规范)
- babel-preset-stage
npm install @babel/preset-env --save-dev
编译 ES6 的方法
babel-polyfill 在打包代码里注入一个全局对象里,对象里定义了 ES6 所有的方法的 ES5 实现。适用于项目开发。
可以在入口文件中直接import 'babel-polifill' 也可以在 entry 中新增 babel-polyfill
babel-plugin-transform-runtime 生成一个局部对象,只会生成使用过的方法的实现。一般适用于框架开发。严格控制大小。
npm install babel-polyfill --save-dev
npm install @babel/plugin-transform-runtime @babel/runtime --save
webpack 配置
module.exports = {
entry: {
app: "./app.js",
},
output: {
filename: "[name].[hash:8].js",
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
targets: {
browsers: [">1%"],
},
},
],
],
},
},
},
],
},
};
编译 Typescript
- 安装 Typescript 和 ts-loader
- 写入 webpack.config.js
- 配置 tsconfig.json
编译 css
css-loader,让css可以被js正确的引入style-loader,让css被引入后可以正确的以一个style标签插入页面- 必须先过
css-loader,再过style-loader
style-loader 的一些配置项
insertAt:style标签插入在哪一块区域insertInto: 插入指定的domsingleton: 是否合并为一个style标签transform: 在浏览器环境下,插入style到页面前,用js对css进行操作
css-loader 的一些核心配置
minimize: 是否压缩(webpack4以上不支持这个,推荐使用uglifyjsWebpackPlugin)module: 是否进行css模块化alias:css中的全局别名(webpack4以上不支持这个)
less,sass
是 css 的预处理语言
less: less,less-loader sass: sass-loader, node-sass
{
rules: [
{
test: /\.less$/,
use: [{
loader: "style-loader",
options: {
// insertInto: "xxx",
singleton: true,
transform: "./transform.js"
}
},
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[path][name]_[local]_[hash:4]"
}
}
},
{
loader: "less-loader"
}]
},
],
}
提取 css 代码
extract-text-webpack-plugin把 css 提取为单独的文件
{
rules: [
{
test: /\.less$/,
use: extractTextCss.extract({
fallback: {
loader: "style-loader",
options: {
// insertInto: "xxx",
singleton: true,
transform: "./transform.js"
}
},
use: [
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[path][name]_[local]_[hash:4]"
}
}
},
{
loader: "less-loader"
}
]
})
},
],
// ...
plugins: [
new extractTextCss({filename: '[name].min.css'})
]
}
css 兼容性处理
post-css,再配合 browserlist
HTML 的处理和打包
html-webpack-plugin
filename指定打包生成的html的名字template指定一个html文件为模板minify压缩htmlinject是否把js,css文件插入到html,插入到哪里chunks多入口时,指定引入chunks
new htmlWebpackPlugin({
filename: "index.html",
template: "./index.html",
});
环境变量
env 参数可以根据不同的指定,产生不同的配置文件,用来适应生产、测试、开发环境的不同需求
图片处理
url-loader,file-loader,img-loader
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'file-loader',
options: {
name:'[name].[hash].[ext]',
outputPath: '',
publicPath: ''
}
}
}
url-loader 可以多一些参数配置
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
name:'[name].[hash].[ext]',
outputPath: '',
publicPath: '',
limit: 5000 //可以将小的资源文件进行base64转码
}
}
}
img-loader 可以进行图片压缩
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [{
loader: 'url-loader',
options: {
name:'[name].[hash].[ext]',
outputPath: '',
publicPath: '',
limit: 5000 //可以将小的资源文件进行base64转码
}
}, {
loader: 'img-loader',
options: {
plugins: [
require('imagemin-pngquant')({
speed: 5 // 1-11,越大,压缩率越小
}),
require('imagemin-mozjpeg')({
quality: 80 // 1-100,质量,压缩率
}),
require('imagemin-gifsicle')({
optimizationLevel: 1, // 1-3
}),
]
}
}]
}
代码分割
多入口要配置多个 HTMLWebpackPlugin,filename 和 chunks 也要指定好
多页面应用时需要提取公共依赖,打包成一个文件。(主业务代码+公共依赖+第三方包+webpack 运行代码)
单页面应用主要是把需要异步加载改成异步加载,把业务代码和第三方代码拆分,保持纯净。(主业务代码+异步模块+第三方包+webpack 运行代码)
- webpack3, commonChunksPlugin
- webpack4, SplitChunksPlugin
{
optimization: {
splitChunks: {
// initial, all ,async
chunks: "initial",
minSize: 0,
// 自定义提取
cacheGroups: {
vendor: {
test: /([\\/]node_modules[\\/])/,
name: 'vendor',
chunks: 'all'
}
}
},
// webpack运行时代码
runtimeChunk: true,
}
}
异步模块加载,命名
import(/* webpackChunkName:"mA" */ "./moduleA.js");
require.ensure([], function () {
require("./moduleA.js");
});
清除之前的 dist, clean-webpack-plugin
{
new CleanWebpackPlugin(),
}
体积优化
- webpack3 optimize.UglifyJsPlugin()
- webpack4 optimization.minimize
打包加速
项目本身
- 减少依赖嵌套深度
- 使用尽可能少的处理
webpack 层面
- dll 处理
- 通过 include 减少 loader 范围
- HappyPack
- Uglify 优化
- 减少 resolve,sourcemap,cache-loader,用新版本的 node 和 webpack
// webpack.config.js
{
new webpack.DllReferencePlugin({
manifest.require('./src/dll/jquery.json')
})
}
// webpack.dll.js
const webpack = require("webpack");
module.exports = {
entry: {
jquery: ["jquery"],
loadsh: ["loadsh"],
},
output: {
path: dirname + "/src/dll",
filename: "./[name].js",
//引用名
library: "[name]",
},
plugins: [
new webpack.DllPlugin({
path: __dirname + "/src/dll/[name].json",
name: "[name]",
}),
],
};
先运行 webpack --config webpack.dll.js,生成对应文件,之后就可以加速了。
长缓存优化
hash->chunkhashNamedChunksPlugin和NamedModulesPlugin