webpack知识
前端工程化:模块化,组件化,规范化,自动化(自动化构建,自动化部署,自动化测试)
使用webpack作为前端构建工具:
- 代码优化:ts编译成js;less/sass编译成css等
- 文件优化:压缩js、css、html代码,压缩合并图片等
- 代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载
- 模块合并:在采用模块化的项目中会有很多个模块和文件,需要构建功能把所有模块合并成一个文件
- 自动刷新:监听本地源代码的变化,自动重新构建代码,刷新浏览器
- 代码检验:在代码被提交到仓库前需要检验代码是否符合规范,以及单元检测是否通过
- 自动发布:更新完代码后,自动构建出线上发布的代码,并传输给发布系统
** 在webpack
应用中有两个核心 **:
- 模块转化器 loader:用于把模块原内容按照需求转换成新内容,可以加载非JS模块
- 扩展插件 plugins:在webpack构建流程中的特定时机注入扩展逻辑来改变构建结果或做想要完成的事
安装 webpack
第一步 项目初始化:npm init -y
第二步 安装 npm install webpack webpack-cli
打包:
-
采用零配置的方式:
npm 版本在5.2之后提供一个打包webpack的命令 npx
在命令行直接输入:npx webpack
默认会把文件打包在一个 dist 的文件夹中 -
配置命令:在package.json文件中的 scripts 下面配置命令,例如配置为 “dev”: “webpack”
配置好之后在命令行输入 nnpm run dev即可实现webpack打包
webpack.config.js 基于nodeJS,所以遵循 commonJS 规范
常用插件
- 清除目录的插件:clean-webpack-plugin
- 打包html插件,根据模板html,把打包的js文件自动插入到html中:html-webpack-plugin
- webpack-dev-server命令:创建本地服务器,自动重新构建,自动打开浏览器并刷新(这个是先去package.json文件中进行命令配置,再去webpack.config中进行配置)
!! 安装 webpack-dev-server 的时候一点要注意webpack-cli的版本,只有两个的版本都是3.x的才有效,否则会报错 - 分离css插件:mini-css-extract-plugin 实现将css样式单独打包成一个文件,通过外链样式引入的
常用 loader
配置加载器需要到 webpack.config.js 中的 module下面进行配置
-
解析css
css-loader:解析css的加载器
style-loader:把解析后的css通过style标签引入到页面中 -
解析css预处理器
- 解析less
less:
less-loader - 解析sass
sass:
node-sass:
sass-loader - 解析stylus
stylus
stylus-loader
- 解析less
-
样式处理工具:postcss-loader 处理css3的私有前缀
这个工具可以放很多插件,各个插件功能不同,所以配置一个文件 postcss.config.js- autoprefixer 私有前缀插件
配置完了发现没有添加前缀,是因为还需要配置一个浏览器覆盖文件 .browserslistrc,在文件中写: cover: 99.9%
- autoprefixer 私有前缀插件
压缩文件的插件
默认运行 webpack --mode production 指令,只会压缩html和js文件,对于css文件是不会进行压缩的,想要同时将这些文件进行压缩,所以安装配置不同的插件
- terser-webpack-plugin 压缩JS
- optimize-css-assets-webpack-plugin 压缩CSS
然后在 webpack.config.js文件中进行配置(这两个插件是生产坏境的,安装的时候不需要加 -D)
注意:这两个插件不是配置在plugins中,而是单独配置在 optimization属性中
处理图片
- file-loader 打包图片并返回打包后图片的路径
- url-loader 将图片转为base64
处理JS模块:将es6/es7/es8转换为es5
代码的转换工作是交给babel处理的
- @babel/core:babel核心模块
- @babel/preset-env:es6转es5插件的集合
- babel-loader:是webpack跟babel的一个桥梁
babel的配置文件 .babelrc
polyfill 处理浏览器相关的api,提高浏览器对js的支持(处理浏览器对JS的兼容问题)
方法一:根据使用的api使用对应的插件方式
问题1:会有很多冗余的代码(使用几次,就转换几次)
问题2:比较麻烦,都需要手动配置
例如:为了处理 Object.assgin引入 @babel/plugin-transform-object-assign
方法二:使用 @babel/plugin-transform-runtime和@bebel/runtime以及 core-js
core-js:转换高版本的api
webpack.config.js文件配置
const path = require('path');
// webpack.config.js文件是基于commonJs规范的,即导入用 require;导出用 module.exports
// 清除打包文件夹的插件
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
// 自动将打包后的js文件引入到html中的插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 分离css的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 压缩JS的插件
const TerserWebpackPlugin = require('terser-webpack-plugin');
// 压缩CSS的插件
const OptimizeAssetsCssWebpackPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
// 配置打包环境是开发环境development还是生产环境production(可以在package.json中进行配置,这里就可以省略了)
// mode: 'development',
// 设置入口文件
entry: './src/index2.js',
// 设置出口文件:包括打包后的文件名,路径等
output: {
// publicPath:'',
// 设置打包后的文件名
filename: 'bundle.js',
// 输出的文件路径
path: path.resolve(__dirname, 'dist'), // 将当前路径和dist合并
},
/* // 设置多入口,多出口
entry: {
// 配置文件名:
// 语法: 打包后的文件名:要打包的文件路径
index: "./src/index.js",
other: "./src/other.js"
},
// 多出口
output: {
filename: "[name].js", // 打包后的文件名,[name]是表示变量,最后名字跟entry中配置的文件名一样
path: path.resolve(__dirname, 'dist'),
}, */
// 配置热更新,打包后的文件是存在内存中(看不到)
// !注意:这里默认打开的是 index.html文件,所以要注意打包后的文件名是不是叫 index.html
devServer: {
// 设置端口
port: 222,
// 自动打开
open: true,
// 开启 gzip 压缩
compress: true,
// 合并路径
contentBase: path.resolve(__dirname, 'static'),
// 配置代理:解决跨域问题
proxy: {
// 对于请求地址中有 /api 的进行相关操作
"/api": {
target: 'url1', //请求的服务地址
secure: false, // true表示是https协议,false表示是http协议
// 重写请求的接口地址
pathRewrite: {
'/api': '', // 将请求地址中的 /api 去掉:例如 http://localhost/api/user:999 -> http://localhost/user:999
},
changeOrigin: true, // 把请求头中的host值改为服务器地址
}
}
},
// 使用额外的插件来实现一些功能(每一个插件都是要先下载,再配置其功能)
// 每安装一个插件或者加载器,在package.json文件中都会有记录
plugins: [
// 插件使用的时候大多都是创建一个插件的实例
// new CleanWebpackPlugin(),
new CleanWebpackPlugin({
// 如果不需要清除dist下的所有文件,则进行其他配置
// aa/*:表示的是 dist/aa下的所有文件
// !aa/bb.js:表示除了 bb.js 文件外
// cleanOnceBeforeBuildPatterns: ['aa/*', "!aa/bb.js"]
}),
// 如果是多入口、多的出口文件,配置 HtmlWebpackPlugin插件的时候一定要记得一个chunks属性,有几个出口文件就配置(创建)几个HtmlWebpackPlugin插件实例
new HtmlWebpackPlugin({
// 配置模板
template: './index.html',
// 是否需要hash
hash: true,
// 设置打包后的文件名(如果想要默认devServer打开,打包后的文件名必须叫 index.html)
// filename: 'home.html', // 只写一个文件名默认都会打包到dist文件夹中
filename: 'index.html',
// 多出口文件必配置的属性 chunks
// chunks: ['index'], // 该文件引入的是那个js文件
}),
// 第二个出口文件配置
// new HtmlWebpackPlugin({
// // 配置模板
// template: './other.html',
// // 是否需要hash
// hash: true,
// // 设置打包后的文件名
// filename: 'other.html', // 只写一个文件名默认都会打包到dist文件夹中
// chunks: ['other']
// }),
// 分离css样式的插件配置
new MiniCssExtractPlugin({
// 设置分离出来的css目录及文件名
filename: 'css/index.css',
})
],
// 配置加载器 loader
module: {
// 匹配规则(一个数组:从后往前找)
rules:[
/* {
test: /\.css$/,
use:'style-loader' // use的值可以是字符串、对象、数组
}, {
test: /\.css$/,
use: 'css-loader'
} */
// 上面两个都是加载css,可以合并成一个对象
// {
// test: /\.css$/,
// // use如果是数组的话,是从右往左找
// use: ['style-loader','css-loader']
// },
// 将css改为通过外链式的方式引入,就不需要上面的那种写法了
// !注意:这个分离只对css为后缀的文件有效,对其他样式无效
{
test: /\.css$/,
use: [
{loader: MiniCssExtractPlugin.loader},
{loader: 'css-loader',
options: {
importLoaders: 2 // 用后面的一个加载器来解析
}}, 'postcss-loader','less-loader'
]
},
// 解析 less文件
{
test: /\.less$/,
use:['style-loader','css-loader', 'less-loader']
},
// 处理图片的加载器的配置
{
test: /\.(jpe?g|peng|gif)$/,
use:{
// loader: 'file-loader',
// 根据图片大小限制来决定是压缩成图片还是转为base64
loader: 'url-loader',
options: {
esModule: false,
limit: 10*1024, // 小于这个的图片基于url-loader转为base64,否则基于file-loader打包图片
// 转为base64的图片打包后是在dist中看不到的
// 指定图片输出的目录,不指定名字和后缀
// outputPath: '/img'
// 配置打包后的图片名及后缀跟打包之前的图片名和格式保持一致
// [name]、[ext] 这是固定的变量格式
name: 'img/[name].[ext]',
// 默认打包后的图片是直接放在dist文件下的
publicPath:'/', // 要设置访问前缀,否则就会爆粗
}
}
},
// 专门处理JS模块的加载器(使用webpack和babel的桥梁插件 babel-loader)
{
test: /\.js$/,
use: 'babel-loader'
}
]
},
// 配置压缩文件的插件
optimization: {
minimizer:[
new TerserWebpackPlugin(),
new OptimizeAssetsCssWebpackPlugin(),
]
}
}
.babelrs文件配置
{
"presets": [
["@babel/preset-env",{
"useBuiltIns": "usage", // 只转化使用的高级api
"corejs": 3 // 转换高版本api
}]
],
"plugins": [
// 这个插件只是转化 Object.assign的,而且使用几次就转换几次,会造成代码冗余
// "@babel/plugin-transform-object-assign"
"@babel/plugin-transform-runtime"
]
}