webpack 仅是一个打包工具,不会处理打包过程的东西例如 es6等新特性,如果需要处理这些新特性需要配置单独的加载bebblle-loader 等。
"devDependencies": {
"webpack": "^5.76.3", // 打包工具
"webpack-cli": "^5.0.1", // 构建打包依赖项目=
"webpack-dev-server": "^4.13.1", // 热更新预览
}
webpack的模块加载,支持一下模块化标准:
但是在项目使用过程中,不建议混合使用,会增加维护难度。
loader 是一个管道,Webpack 可以对同一资源使用多个loader,每个loader 返回一个 js 对象,传到另一个 loader。
babel-loader | 将Es6+ 语法转换为Es5 |
babel-core | loader的核心依赖 |
babel-preset-env | 兼容最新的语法,不用担心浏览器兼容,同时让打包更小,以及es2015的babel |
babel-preset-react | 支持jsx语法 |
css-loader | 用于识别.css文件, 处理css必须配合style-loader共同使用,只安装css-loader样式不会生效。 |
style-loader | 用于将css编译完成的样式,挂载到页面style标签上。 |
file-loader | 把文件、图片等输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 |
url-loader | 和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去 |
sass-loader | css预处理器,我们在项目开发中经常会使用到的 |
postcss-loader | 用于补充css样式各种浏览器内核前缀 |
ts-loader | 用于配置项目typescript |
html-loader | 我们有时候想引入一个html页面代码片段赋值给DOM元素内容使用,这时就用到html-loader,建议安装低版本,高版本可能会不兼容导致报错。 |
eslint-loader | 用于检查代码是否符合规范,是否存在语法错误。 |
vue-loader | 用于编译.vue文件,如我们自己搭建vue项目就可以使用vue-loader |
例如:清除上次结果的目录,拷贝资源文件,压缩代码等。
表头 | 表头 |
---|---|
html-webpack-plugin | 生成 html文件。原因:打包产物是 js,不包含 html,发布的时候比较麻烦,另外 html 引用打包后的 css 、图片,引用等内容路径可能找不到。默认生成index. html,可以使用filename指定html 名称 |
html-webpack-plugin | 清理生成的打包目录 |
copy-webpack-plugin | 复制静态文件。接受一个数组,数组元素是需要拷贝的路径,路径 可以是一个通配符。 |
DefinePlugin | 内置插件。注入全局变量的插件,通常使用该插件来判别代码运行的环境变量 |
minCssExcractPluin | 提取打包的 css 文件,实现 css 加载 |
optimize-css-assets-webpack-plugin | 压缩 css |
1、.babelrc
{
"presets": [
"@babel/preset-env",
[
"@babel/preset-react",
{
"runtime": "automatic"
}
],
"@babel/preset-typescript"
]
}
2、webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: 'development',
entry: './src/index',
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{loader: 'style-loader'},
{loader: 'css-loader'},
]
},
{
test: /\.(png|jpg|gif|svg)$/,
exclude: /node_modules/,
loader: 'file-loader',
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: "23",
template: "public/index.html"
}),
],
};
3、package
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^9.1.2",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"css-loader": "^6.7.3",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"style-loader": "^3.3.2",
"webpack": "^5.76.3",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.13.1"
}
webpack 在打包的时候将会剔除掉被没有被使用到的代码达到减小报体积,缩短 http 请求时间,起到一定效果的页面优化。在webpack5中已经自带tree-shaking功能,在打包模式为production时,默认开启 tree-shaking功能。需要注意的是他不是某一项功能配置的使用,而是一组功能搭配使用后的优化效果,在生产环境自动启动,其他模式下需要手动开启。
webpack.config.js:
optimization: {
usedExports: true, // 负责标记枯树叶
minimize: true , // 负责摇掉枯树枝
concatenateModules: true, //尽可能将所有的模块合并输出到一个函数中,提升运行效率,减少了体积(Scope hoisting)
}
tree sharking vs babel:
tree sharking的实现必须使用 ES Module,但是为了转换新特性,很多时候首页 babel-loader处理 js,处理的过程中可能使用@babel/preset-env将 ES Module转为 commonJs,这时候tree sharking就失效了。
将 modules 改为 false 可以避免,在最新版本的 webpack5已经不存在这个问题了。
sideEffects一般用于 NPM 包标记是否有副作用,和tree sharking没任何关系。
optimization: {
sideEffects: true,
}
// 除此之外还需要在 package 里面配置sideEffects
"sideEffects" : ["文件路径"], 或者 "sideEffects" : true
该功能在打包模式为production时,默认开启,在打包时候回检测是否有标识,有副作用,没有副作用在打包时候不会参与打包。启动该功能时候需要确保没有副作用,否则的话会误删。
如果应用很复杂,打包的bundle 会非常大,导致卡顿,需要分包,按需加载。可以分为多入口打包,一个页面一个入口,公共的抽取。
plugins: [
new HtmlWebpackPlugin({
title: "标题1",
template: "./src/index.html",
filename: "index.html",
chunks: ['index'] // 需要配置chunks
}),
new HtmlWebpackPlugin({
title: "标题2",
template: "./src/album.html",
filename: "album.html",
chunks: ['album'] // 需要配置chunks
}),
],
// 这块是数组,而不是单一入口的文件
entry: {
index: './src/index.js',
album: './src/album.js',
},
output: {
filename: "[name].bundle.js" // name会被替换成入口的名称
}
公共模块抽取:
splitChunks: {
chunks: "all" // 表示将所有的公共模块都提取到单独的bundle.js 中
}
development(开发环境) 和 production(生产环境) 这两个环境下的构建目标存在着巨大差异,通过 webpack-merge 可以将基础的配置抽象到 webpack.base.js 中,开发环境和线上环境分别使用 webpack.dev.js 和 webpack.prod.js,然后 merge(webpack.base.js)即可。
动态导入会被自动的分包,相比多入口的方式,动态导入更加灵活。通过ES Module 的方式:
if (hash === 'album') {
import(/* webpackChunkName : album*/,'./src/album').then(module => {
})
} else {
import(/* webpackChunkName : index*/,'./src/index').then(module => {
})
}
webpackChunkName:给分包起名字,如果名称相同,则打包时候会被打包在一起。
minCssExcractPluin:提取 css 模块,按需加载 css。当超过150KB 建议使用。
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{loader: MinCssExcractPluin.loader},
{loader: 'css-loader'},
]
}
]
},
plugins: [
new MinCssExcractPluin()
],
webpack 在生产模式下内置插件默认只针对于 js 压缩,对于其他文件的压缩需要借助于插件。css 压缩需要用到optimize-css-assets-webpack-plugin,需要注意的是OptimizeCSSAssetsPlugin需要配置在optimization里面,因为配置在plugins针对于全部生效,而配置在optimization里面:
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin(), // 设置该内容后回覆盖系统的 js 压缩插件,导致js 不能被压缩,需要在这再次配置下默认的 js 压缩插件terser-webpack-plugin
new TerserPlugin()
]
}
1、hash:普通 hash全局生效
output: {
filename: "[name]-[hash].bundle.js" // name会被替换成入口的名称
},
plugins: [
new MinCssExcractPluin({
filename: "[name]-[hash].bundle.css"
})
],
2、contenthash:文件 hash,根据文件生成
output: {
filename: "[name]-[contenthash].bundle.js" // name会被替换成入口的名称
},
plugins: [
new MinCssExcractPluin({
filename: "[name]-[contenthash].bundle.css"
})
],
还可以指定缓存的hash 的长度,如下8表示 hash 的长度:
filename: "[name]-[contenthash:8].bundle.css"
解决在编译后代码和源代码不一致引发的调试困难问题。source-map是从已转换的代码,映射到原始的源文件,使浏览器可以重构原始源并在调试器中显示重建的原始源。在 webpack.config.js配置。支持很多种sourceMap,调试效果和打包效率都不一样。常见的如下:
1、eval
每个module会封装到 eval 里包裹起来执行,并且会在末尾追加注释 //@ sourceURL.
2、source-map
生成一个SourceMap文件.
3、hidden-source-map
和 source-map 一样,但不会在 bundle 末尾追加注释.
4、inline-source-map
生成一个 DataUrl 形式的 SourceMap 文件.
5、eval-source-map
每个module会通过eval()来执行,并且生成一个DataUrl形式的SourceMap.
6、cheap-source-map
生成一个没有列信息(column-mappings)的SourceMaps文件,不包含loader的 sourcemap(譬如 babel 的 sourcemap)
7、cheap-module-source-map
生成一个没有列信息(column-mappings)的SourceMaps文件,同时 loader 的 sourcemap 也被简化为只包含对应行的。