Webpack4.0 学习笔记(上)
date
Mar 3, 2020
slug
webpack4.x-note-1
status
Published
tags
Webpack
summary
webpack深入学习笔记,内含常见配置案例
type
Post
webpack是什么?支持的模块的规范loaderloader 就是 webpack 除 js 文件外帮助其识别、处理对应资源的 js 文件pluginplugin 是 webpack 的插件接口,这个插件接口使 webpack 变得极其灵活。原理就是可以在 webpack 运行到某一时刻的时候,帮你做一些事情。(类比生命周期的钩子函数)devServerdevServer 是 webpack 在本地的开发环境下利用 http-proxy-middleware & node 开启的一个服务器webpack 执行方式提示
webpack是什么?
webpack 是模块打包工具,底层的文件处理逻辑全部由 node 完成
支持的模块的规范
webpack 支持多种模块规范,es6: import/export default | common.js: reuqire/moudle.export | AMD: define/require | styles file: @import | resource file:
<img src=...>
。在 webpack 发展初期只是打包 js,但随着发展后现在可以打包 js/css 等文章loader
loader 就是 webpack 除 js 文件外帮助其识别、处理对应资源的 js 文件
- file-loader 就是将图片资源复制粘贴进你配置的打包文件路径中,并将最新的符合你配置规则的图片名称(路径)返回,供代码使用
- ['style-loader', 'css-loader'] 先执行 css-loader 分析清楚 css 间的关系,并将其整合为一个 css 文件;style-loader 则将这个 css 文件挂载到 html 的 head 底部。
- css-loader 的 options 中设置
importLoaders: 2
指的是 index.scss 中 @import 了 a.scss,a.scss 中 @import 了 b.scss,如果不加这一项就会导致 b.scss 无法走 scss-loader 设置这个的目的就是为了确保 b.scss 先走 postcss-loader =》scss-loader 再走 css-loader =》style-loader
- css moudle 的配置需要在 css-loader 的 option 中设置
modules: true
即可使用style.xxx
plugin
plugin 是 webpack 的插件接口,这个插件接口使 webpack 变得极其灵活。原理就是可以在 webpack 运行到某一时刻的时候,帮你做一些事情。(类比生命周期的钩子函数)
- html-webpack-plugin: 该插件将为你生成一个 HTML5 文件, 并将打包生成的 js 自动插入到这个 html 中。当 webpack 打包资源结束这个时刻开始工作
- clean-webpack-plugin: 该插件当 webpack 打包前这个时刻先删除之前的打包文件(dist)
- webpack.HotMoudleReplacementPlugin() HMR 指的是在不刷新 .html 文件下只更新(保留当前页面的状态包括js结果)变动的代码(样式等)对应的在 devserver 中需要开启 hot/hotOnly
devServer
devServer 是 webpack 在本地的开发环境下利用 http-proxy-middleware & node 开启的一个服务器
这里主要说一下 proxy 的配置,如下:
module.exports = {
// ...
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true,
proxy: {
'/api': {
target: 'https://www.xxx.com',
secure: false,
pathRewrite: {
'info.json': 'demo.json'
},
changeOrigin: true,
headers: {
cookie: 'xxx'
}
}
}
}
}
- target 指接口转发的目标地址,如果目标使用了 https 协议,那么必须带上 secure: false,如果是 http,则可以不配置 secure 或者使其为 true
- pathRewrite 常用应用场景是后台正在开发接口,但是你这边需要数据,后端给了一个 mock 数据的接口,但是在业务代码中你又不想修改 info.json 为 demo.json,所以在这里进行配置后期注释掉即可
- changeOrigin 是修改发起请求的头信息,主要是为了防止转发的目标地址会对头信息做限制,导致拿不到数据
- headers 中设置一些头信息、cookie 主要用来模拟登陆状态
webpack 执行方式
提示
- npx 想要解决的主要问题,就是调用项目内部安装的模块
- npx create-react-app my-react-app 避免全局安装模块
- url-loader 中包含 file-loader 这俩者都能处理资源(图片、字体等)但是 url-loader 的好处就是可以转换将图片自动转为 base64
- output 中配置 cdn/oss 地址需要配置 publicPath 可以使用相关的 plugin 进行上传
- sourcemap 是一个映射 src 到 dist 中代码的映射关系
- 需要注意的点是 babel:
// 该方案只针对于业务代码
// npm install --save-dev babel-loader @babel/core
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
// 正常情况下我们是这样配置 babel 的,但如果在代码中使用了低版本浏览器不兼容的 promise、map 等方法该怎么办?
// npm install --save @babel/polyfill
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', {
targets: {
chrome: '67'
},
useBuiltIns: 'usage'
}]]
}
}
// 这样配置后只需要在使用 es6 语法的地方 import "@babel/polyfill" 即可,但这
// 样的问题是原本可能只有10多k大小的文件引入polyfill后变成上百k,但其实代码里只用
// 到了 promise,这个时候就需要配置 useBuiltIns: 'usage' 这样就只会引入
// promise 相关的 polyfill,targets 的作用是当浏览器小于某个版本时才进行
// babel 的转换
// webpack4 中不用在文件中 import "@babel/polyfill" 配置 useBuiltIns: 'usage' 后 babel 自动加上 polyfill
// 该方案只针对于与业务无关的插件、类库等三方代码
// 为什么这样做?因为 polyfill 会将方法注入至全局,污染全局环境
// npm install --save-dev babel-loader @babel/core
// npm install --save-dev @babel/plugin-transform-runtime
// npm install --save @babel/runtime-corejs
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
plugins: [['@babel/plugin-transform-runtime', {
corejs: 2,
helper: true,
regenerator: true,
useESModules: false
}]]
}
}
// 去掉代码中的 import "@babel/polyfill" 然后执行即可
// 如果 options 中配置参数较多可以将 options 对象直接提出放至项目根目录的 .babelrc 中即可
- 所有 loader 或者 loader 中的 options 配置执行顺序都是从下往上、从右往左
- 开启了 hotOnly: true 后局部更新后页面不会自动刷新
- 开启 devserver 后打包文件存在于内存中,想查看的话可以通 `npx webpack --config webpack.dev.config` 来避开 `webpack-dev-server --config webpack.dev.config`
- 前端spa路由需要注意的一个点是要配置 `historyApiFallback: true` 这样才能保证在地址栏输入路径后不被 devServer 的代理当作接口转发走
- resolve 的配置:
module.exports = {
// ...
resolve: {
// 配置 extensions 可以免去写文件后缀名,但是尽量不要也将资源类文件的后缀配进来(因为每次查找文件会使用node的fs模块,性能会受影响)
extensions: ['.js', '.jsx'],
// 配置 mainFiles 可以在引入时只写目录 eg: `import Child from './src/child'`,这样 webpack 会先找 child 目录下的 indexjs 没有的话会找 childjs
mainFiles: ['index', 'child'],
// 配置 alias 就可以使用别名
alias: {
i7eo: path.resolve(__dirname, './src/child')
}
}
}