webpack 的用途
- 帮我们处理 依赖的文件(依赖的资源)
- 转换 依赖的模块 (浏览器不支持的模块)
- 项目优化
先初始化
npm init -y 初始化后会自动创建package.json文件
本地安装webpack
npm install webpack webpack-cli --save-dev
查看webpack 版本
webpack -v
npm 的版本在5.2以上 就可以用 npx
0 配置打包
npx webpack
在 package.json文件中手动设置 执行的命令
"scripts": {
// "test": "echo \"Error: no test specified\" && exit 1"
用下面这些写法 把上面的这一步删除
"dev": "webpack --mode development", // 开发环境
"build":"webpack --mode production", // 生产环境
"dev:server": "webpack-dev-server"
自己配置好后 用 npm run dev / build / dev:server 去使用
}
将每次打包后的js要插入到html中,在浏览器端查看(需要下载下面这个插件)然后再webpack.config.js中引入
npm i --save-dev html-webpack-plugin (开发依赖)
配置本机的开发服务(自动帮我们启动一个服务 并且在浏览器中打开) (这个插件是一个命令,需要自己去package.json文件中的 scripts中配置)
这个插件打包的内容是在保存在内存里面的 我们是看不到的
npm install webpack-dev-server --save-dev
加载css需要两个loader
npm install --save-dev css-loader npm install --save-dev style-loader
加载less
npm install --save-dev less less-loader
样式处理工具 可以借助自定义的插件从而重新定义css
加私有前缀的插件 autoprefixer
需要在根目录下创建一个 postcss.config.js文件 在这里面去引入自定义的插件
需要在根目录下再创建一个.browserslistrc文件 里面填写参数 cover 99.5% 可以覆盖99.5%的浏览器 这样不同的浏览器都会加上前缀(不论高版本还是低版本)
npm i -D postcss-loader autoprefixer
分离出来css文件
npm install --save-dev mini-css-extract-plugin
压缩js文件(生产环境) 不加D是生产环境下
npm install terser-webpack-plugin
压缩css文件(生产环境) 不加D是生产环境下
npm install optimize-css-assets-webpack-plugin
清理输出的目录(每一次打包都会清理dist里面的内容)
npm install --save-dev clean-webpack-plugin
file-loader url-loader
file-loader: 加载图片 把图片拷贝到 dist目录下
url-loader: 把图片解析成base64
npm install file-loader url-loader --D ( 给 url-loader的 options下面加一个 esModule: false 必须加 )
专门用来处理html文件中的图片
npm install html-withimg-loader --save
解决办法:esModule: false // 该项默认为true,改为false即可
esModule: true该配置项为图片打包后的默认路径,带default对象,
默认为ture,在配置项里将此项改为false即可去掉多余的defalut
对象,
babel
npm install babel-loader @babel/core @babel/preset-env --D
babel-loader babel和 webpack的桥梁(webpack可以通过babel来编译我们的代码)(匹配 js后缀的文件 解析)
@babel/core babel的核心模块(放了babel所有的核心模块)(在核心模块里设置一些预设 或者插件)
@babel/preset-env 主要是把ES6 转换为 ES5 它是一个插件的集合(预设)
npm install --save core-js@3
类似于 babel/polyfill 可以解析高版本的语法
@babel/plugin-transform-runtime @babel/runtime
第一个插件 调用第二个插件 解决冗余(多余)的代码 把公共的方法提取出来
解决草案的插件
npm install --save-dev @babel/plugin-proposal-class-properties
npm install --save-dev @babel/plugin-proposal-decorators // 解决装饰器
装饰器的插件必须在 类插件的前面 如果装饰器的"legacy": true 那么必须 “loose”: true
npm install jquery -D
暴露全局变量 (暴露第三方库)
1、直接使用cdn的方式
2、providePlugin "$":"jquery"
3、暴露的方式 expose-loader (npm install expose-loader -D)
添加eslint.js
1、手动 (去官网 https://eslint.org/demo 里面下载 eslintrc.json 拉过来调用)
npm install eslint eslint-loader -D
2、自动
npx eslint --init (初始化配置文件)
sourceMap(代码排查错误)
- eval 生成代码 每个模块都被 eval执行,每一个打包后的模块后面都增加了包含 sourceURL
- source-map 产生map文件
- inline 不会生成独立的 .map文件,会以dataURL形式插入
- cheap 忽略打包后的列信息,不使用 loader中的 sourcemap
- module 没有列信息,使用loader中的 sourcemap(没有列信息)
开发环境推荐: cheap-module-eval-source-map
生产环境推荐: cheap-module-source-map
图片压缩
npm install image-webpack-loader --save-dev
Tree-shaking(生产环境下)(副作用 无作用的代码)
- sideEffects 唯一一个设置在package.json的配置
“sideEffects”: [ “**/*.css” ], 生产环境下打包才有用 开发环境下 无效
Scope-Hoisting
webpack4 后不用配,天生自带 减少作用域提升性能
热更新
css 自带热更新效果 我们把css样式抽离后 就无发实现热更新 css热更新是在(style-loader里面去设置控制)
- hot:true
- HotModuleReplacementPlugin
- module.hot.accept
懒加载(动态加载)
- webpackChunkName(可以设置动态加载出来的文件名) chunkFilename
- webpackPrefetch
- webpackPreload
- @babel/plugin-syntax-dynamic-import
- @babel/preset-react
打包文件分析工具(生成环境下使用)
默认就会展现当前应用的分析图表
安装webpack-bundle-analyzer插件
npm install --save-dev webpack-bundle-analyzer
const {BundleAnalyzerPlugin} = require(‘webpack-bundle-analyzer’);
DllPlugin & DlLReferencePlugin (一般用在开发环境下)
把第三方库打包成动态链接库,以后构建时只需要查找构建好的库就好了,这样可以大大节约构建时间
-add-asset-html-webpack-plugin
多入口多出口
SplitChunks
编译时抽离第三方模块、公共模块
happypack
多线程打包,可以讲不同的逻辑交给不同的线程来处理
根据Mode分离配置环境
// 遵循 commonjs 规范
const path = require('path')
// 引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入分离css的插件
const MiniExtractPlugin = require("mini-css-extract-plugin")
const TerserJSPlugin = require('terser-webpack-plugin'); // 压缩js
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩css
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpack = require("webpack")
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
let htmlPlugins = ["index", "other"].map(chunkName => {
return new HtmlWebpackPlugin({
// 把打包后的js自动的引用到新生成的html文件中
template: path.resolve(__dirname, `./${chunkName}.html`),
filename: `${chunkName}.html`,
minify: false,
chunks: [`${chunkName}`]
})
})
module.exports = {
devtool: "cheap-module-eval-source-map", // 代码报错后 【准确】显示出来哪一行 为何报错
// externals: {
// "jquery": "$" // 如果是第三方库jQuery就需要打包
// },
// 抽离公共的库 第三方模块
optimization: {
splitChunks: {
chunks: 'all', // async 异步代码 all 所有
minSize: 30000, // 最少30kb采取抽离
minRemainingSize: 0,
maxSize: 0,
minChunks: 1, //最少引用模块一次
maxAsyncRequests: 6, // 异步模块请求最多不超过6次
maxInitialRequests: 4, // 首屏请求次数不超过3次
automaticNameDelimiter: '~', // 抽离模块名称的连接符
name: true, // 可以更改模块名
cacheGroups: { // 自己设定一些规则
// defaultVendors: {
// test: /[\\/]node_modules[\\/]/,
// priority: -10 // 优先级
// },
default: { // 抽离的模块名 名字默认是 default开头
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
},
/*
entry: 入口文件
output: 出口文件
filename: 用于设置打包的 js文件名字
path: 打包后的路径
__dirname: commonjs 规范里面提供的 API 主要目的 定位所在文件的项目根目录
*/
entry: { // 配置多入口多出口
index: "./src/index.js",
// other: "./src/other.js"
},
output: {
filename: "[name].js", // chunkhash 是以入口文件为基准的hash值 content 是以文件为基准的hash值
path: path.resolve(__dirname, "dist"), // 这一步返回一个绝对的路径
chunkFilename: "[name].min.js" // 设置异步请求的文件名
},
// webpack4 提供的压缩选项
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
devServer: {
port: 7878, // 端口号
// open: true, // 打包后 自动打开
compress: true, // 启动gzip压缩
contentBase: "aa", // aa目录下的静态资源文件也可以直接访问
// 若是要访问 aa静态资源里面的内容 直接在自动打开的浏览器窗口地址中输入你想要打开的静态资源 是帮我们配置好的
//比如 这个是自动打开的地址 http://localhost:9999 想要打开静态资源直接在后面输入即可 http://localhost:9999/a.html
// 模拟数据(后端数据没写好之前)
before(app) { // after 以9999端口号创建一个服务,这样没有跨域问题
app.get("/api/user", function (req, res) {
console.log(res.json({ name: "xw" }));
})
},
hot: true
// proxy: {
// // 配置跨域请求
// "/api": {
// target: "http://localhost:6000", // 设置请求的服务器地址
// pathRewrite: { "/api": "" }, // 重写路径
// changeOrigin: true // 把请求头里面 host的地址改成服务器地址(为true表示是6000当前服务器的地址,为false表示服务器端的接口地址)
// // secure: false // 代理的服务器是 https
// }
// }
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(),
// new MiniExtractPlugin({
// filename: "css/main.css"
// }),
new HtmlWebpackPlugin({
// 把打包后的js自动的引用到新生成的html文件中
template: path.resolve(__dirname, "./index.html"),
filename: "index.html",
minify: false,
// chunks: ["index"]
}),
// new HtmlWebpackPlugin({
// // 把打包后的js自动的引用到新生成的html文件中
// template: path.resolve(__dirname, "./other.html"),
// filename: "other.html",
// minify: false,
// chunks: ["other"]
// }),
// ...htmlPlugins,
// new webpack.ProvidePlugin({ // 可以把变量变成每个模块都能使用的,但是并不是window上的 这个插件需要配合cdn一起使用
// "$": "jquery" // $ 变量 是jQuery中的
// })
// 分析图表
// new BundleAnalyzerPlugin()
],
module: { // 确定下对什么文件进行转换,怎么转换,需要哪些loader
rules: [ // rules 是从下往上进行解析的,从右往左,确定好规则
// {
// test: /\.css$/, // 匹配文件
// use: "style-loader" // use 后面的值可以是 空对象("") 数组([]) 对象({})
// },
// {
// test: /\.css$/,
// use: "css-loader"
// }
{
// eslint 要在所有规则之前配置
test: /\.js$/,
use: "eslint-loader",
exclude: /node_modules/, // 排除哪些文件
// include: path.resolve(__dirname, "src/**/*"), // 校验包含哪些文件
enforce: "pre" // 在所有规则之前先校验代码
},
{
test: require.resolve("jquery"),
use: {
loader: "expose-loader",
options: "$"
}
},
{
test: /\.css$/,
use: [//"style-loader", // 把css分离出来不用 "style-loader" 用 "link" 因为js是单线程 所以要用link 可以提高css加载速率
// {
// loader: MiniExtractPlugin.loader
// },
{
loader: "style-loader"
},
{
loader: "css-loader",
options: {
importLoaders: 2 // 用后面几个加载器解析 写几个就用几个
}
}, "postcss-loader", "less-loader"
]
},
{
// 配置less
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"]
},
// {
// test: /\.(png|jpe?g|gif)/,
// use: "file-loader"
// }
{
// 把图片转换为base64
test: /\.(png|jpe?g|gif)$/,
// 10kb 以内的通过url-loader转换成 base64,大于 10kb的通过file-loader拷贝一份放在dist目录下
use: [
// loader: "url-loader",
// options: {
// limit: 10 * 1024, // 110kb
// outputPath: 'img', // 设置图片的存放路径
// // publicPath: "xiaoyu/img" // 把图片放到别的服务器中 并设置绝对路径前缀
// esModule: false // 该项默认为true,改为false即可
// }
// 下面是配置压缩图片
{ loader: "file-loader" },
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
// optipng.enabled: false will disable optipng
optipng: {
enabled: false,
},
pngquant: {
quality: [0.65, 0.90],
speed: 4
},
gifsicle: {
interlaced: false,
},
// the webp option will enable WEBP
webp: {
quality: 75
}
}
}
]
},
{
// 配置 iconfont 字体图标
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: "file-loader"
},
{
test: /\.html$/,
use: "html-withimg-loader"
},
{
// 配置babel (可以专门创建一个文件.babelrc 用来存储预设或者插件 因为后期要配多个)
test: /\.js$/,
use: {
loader: "babel-loader",
// options: { 把options里面的配置放到 .babelrc文件中
// presets: ["@babel/preset-env"], // 预设 也就是插件的集合
// plugins: [] // 放置一个个的插件
// }
}
}
]
}
}
.browserslistrc 文件中的代码如下
cover 99.5%
//适配 99.5% 的浏览器
postcss.config.js 文件中的代码如下
module.exports = {
plugins: [
require("autoprefixer")
]
}
// (加前缀 不论高低版本)