快捷搜索:  汽车  科技

webpack 详细教程:带你深度解读Webpack系列 进阶篇

webpack 详细教程:带你深度解读Webpack系列 进阶篇<!-- index.html --> <script src="./js/base.js"></script>这时候,我们 npm run dev,会发现有找不到该资源文件的报错信息。├── public │ ├── config.js │ ├── index.html │ ├── js │ │ ├── base.js │ │ └── other.js现在,我们在 index.html 中引入了 ./js/base.js。1.静态资源拷贝有些时候,我们需要使用已有的JS文件、CSS文件 (本地文件),但是不需要 webpack 编译。例如,我们在 public/index.html 中引入了 public 目录下的 js 或 css 文件,这个时候,如果直接打包,那么在构建出来之后,肯定是找不到对应的 js

三篇长文,带你解读 webpack,希望读完这三篇文章,你能够对 webpack 的各项配置有一个更为清晰的认识。

本文是第二篇,如果你还没有阅读我的上一个文章,建议阅读之后,再继续阅读本文。

本文会引入更多的 webpack 配置,如果文中有任何错误,欢迎再评论区指正,我会尽快修正,webpack 优化部分放在了下一篇。

推荐大家参考本文一步一步进行配置,不要总是想着找什么最佳配置,掌握之后,根据自己需求配置出来的,就是最佳配置。

webpack 详细教程:带你深度解读Webpack系列 进阶篇(1)

1.静态资源拷贝


有些时候,我们需要使用已有的JS文件、CSS文件 (本地文件),但是不需要 webpack 编译。例如,我们在 public/index.html 中引入了 public 目录下的 jscss 文件,这个时候,如果直接打包,那么在构建出来之后,肯定是找不到对应的 js / css 了。

public 目录结构

├── public │ ├── config.js │ ├── index.html │ ├── js │ │ ├── base.js │ │ └── other.js

现在,我们在 index.html 中引入了 ./js/base.js

<!-- index.html --> <script src="./js/base.js"></script>

这时候,我们 npm run dev,会发现有找不到该资源文件的报错信息。

对于这个问题,我们可以手动将其拷贝至构建目录,然后配置 CleanWebpackPlugin 时,注意不要清空对应的文件或文件夹即可,但是如若这个静态文件时不时的还会修改下,那么依赖于手动拷贝,是很容易出问题的。

不要过于相信自已的记性,依赖于手动拷贝的方式,大多数人应该都有过忘记拷贝的经历,你要是说你从来没忘记过。

webpack 详细教程:带你深度解读Webpack系列 进阶篇(2)

幸运的是,webpack 为我们这些记性不好又爱偷懒的人提供了好用的插件 CopyWepackPlugin,它的作用就是将单个文件或整个目录复制到构建目录。

首先安装一下依赖:

npm install copy-webpack-plugin -D

修改配置(当前,需要做的是将 public/js 目录拷贝至 dist/js 目录):

//webpack.config.js const CopyWebpackPlugin = require('copy-webpack-plugin'); module.exports = { //... plugins: [ new CopyWebpackPlugin([ { from: 'public/js/*.js' to: path.resolve(__dirname 'dist' 'js') flatten: true } //还可以继续配置其它要拷贝的文件 ]) ] }

此时,重新执行 npm run dev,报错信息已经消失。

这里说一下 flatten 这个参数,设置为 true,那么它只会拷贝文件,而不会把文件夹路径都拷贝上,大家可以不设置 flatten 时,看下构建结果。

另外,如果我们要拷贝一下目录下的很多文件,但是想过滤掉某个或某些文件,那么 CopyWebpackPlugin 还为我们提供了 ignore 参数。

//webpack.config.js const CopyWebpackPlugin = require('copy-webpack-plugin'); module.exports = { //... plugins: [ new CopyWebpackPlugin([ { from: 'public/js/*.js' to: path.resolve(__dirname 'dist' 'js') flatten: true } ] { ignore: ['other.js'] }) ] }

例如,这里我们忽略掉 js 目录下的 other.js 文件,使用 npm run build 构建,可以看到 dist/js 下不会出现 other.js 文件。CopywebpackPlugin 还提供了很多其它的参数,如果当前的配置不能满足你,可以查阅文档进一步修改配置。

2.ProvidePlugin


ProvidePlugin 在我看来,是为懒人准备的,不过也别过度使用,毕竟全局变量不是什么 "好东西"。ProvidePlugin 的作用就是不需要 import require 就可以在项目中到处使用。

ProvidePluginwebpack 的内置插件,使用方式如下:

new webpack.ProvidePlugin({ identifier1: 'module1' identifier2: ['module2' 'property2'] });

默认寻找路径是当前文件夹 ./**node_modules 当然啦,你可以指定全路径。

React 大家都知道的,使用的时候,要在每个文件中引入 React,不然立刻报错给你看。还有就是 jquerylodash 这样的库,可能在多个文件中使用,但是懒得每次都引入,好嘛,一起来偷个懒,修改下 webpack 的配置:

const webpack = require('webpack'); module.exports = { //... plugins: [ new webpack.ProvidePlugin({ React: 'react' Component: ['react' 'Component'] Vue: ['vue/dist/vue.esm.js' 'default'] $: 'jquery' _map: ['lodash' 'map'] }) ] }

这样配置之后,你就可以在项目中随心所欲的使用$、_map了,并且写 React 组件时,也不需要 import ReactComponent 了,如果你想的话,你还可以把 React Hooks 都配置在这里。

另外呢,Vue 的配置后面多了一个 default,这是因为 vue.esm.js 中使用的是 export default 导出的,对于这种,必须要指定 defaultReact 使用的是 module.exports 导出的,因此不要写 default

另外,就是如果你项目启动了 eslint 的话,记得修改下 eslint 的配置文件,增加以下配置:

{ "globals": { "React": true "Vue": true //.... } }

当然啦,偷懒要有个度,你要是配一大堆全局变量,最终可能会给自已带来麻烦,对自已配置的全局变量一定要负责到底。

webpack 详细教程:带你深度解读Webpack系列 进阶篇(3)

3.抽离CSS


CSS打包我们前面已经说过了,不过呢,有些时候,我们可能会有抽离CSS的需求,即将CSS文件单独打包,这可能是因为打包成一个JS文件太大,影响加载速度,也有可能是为了缓存(例如,只有JS部分有改动)还有可能就是 "我高兴":我想抽离就抽离,谁也管不着。

不管你是因为什么原因要抽离CSS,只要你有需求,我们就可以去实现。

首先,安装 loader

npm install mini-css-extract-plugin -D

mini-css-extract-plugin 和 extract-text-webpack-plugin 相比:

  1. 异步加载
  2. 不会重复编译(性能更好)
  3. 更容易使用
  4. 只适用CSS

修改我们的配置文件:

//webpack.config.js const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name].css' //个人习惯将css文件放在单独目录下 //publicPath:'../' //如果你的output的publicPath配置的是 './' 这种相对路径,那么如果将css文件放在单独目录下,记得在这里指定一下publicPath }) ] module: { rules: [ { test: /\.(le|c)ss$/ use: [ MiniCssExtractPlugin.loader //替换之前的 style-loader 'css-loader' { loader: 'postcss-loader' options: { plugins: function () { return [ require('autoprefixer')({ "overrideBrowserslist": [ "defaults" ] }) ] } } } 'less-loader' ] exclude: /node_modules/ } ] } }

现在,我们重新编译:npm run build,目录结构如下所示:

. ├── dist │ ├── assets │ │ ├── alita_e09b5c.jpg │ │ └── thor_e09b5c.jpeg │ ├── css │ │ ├── index.css │ │ └── index.css.map │ ├── bundle.fb6d0c.js │ ├── bundle.fb6d0c.js.map │ └── index.html

前面说了最好新建一个 .browserslistrc 文件,这样可以多个 loader 共享配置,所以,动手在根目录下新建文件 (.browserslistrc),内容如下(你可以根据自己项目需求,修改为其它的配置):

last 2 version > 0.25% not dead

修改 webpack.config.js

//webpack.config.js const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { //... plugins: [ new MiniCssExtractPlugin({ filename: 'css/[name].css' }) ] module: { rules: [ { test: /\.(c|le)ss$/ use: [ MiniCssExtractPlugin.loader 'css-loader' { loader: 'postcss-loader' options: { plugins: function () { return [ require('autoprefixer')() ] } } } 'less-loader' ] exclude: /node_modules/ } ] } }

要测试自己的 .browserlistrc 有没有生效也很简单,直接将文件内容修改为 last 1 Chrome versions ,然后对比修改前后的构建出的结果,就能看出来啦。

将抽离出来的css文件进行压缩:

使用 mini-css-extract-pluginCSS 文件默认不会被压缩,如果想要压缩,需要配置 optimization,首先安装 optimize-css-assets-webpack-plugin.

npm install optimize-css-assets-webpack-plugin -D

修改webpack配置:

//webpack.config.js const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { entry: './src/index.js' //.... plugins: [ new OptimizeCssPlugin() ] }

注意,这里将 OptimizeCssPlugin 直接配置在 plugins 里面,那么 jscss 都能够正常压缩,如果你将这个配置在 optimization ,那么需要在配置一下 js 的压缩(开发环境下不需要去做CSS的压缩,因此后面记得将其放到 webpack.config.prod.js 中哈)。

配置完之后,测试的时候发现,抽离之后,修改 css 文件时,第一次页面会刷新,但是第二次页面不会刷新不会刷新 —— 好嘛,我平时的业务中用不着抽离 css,这个问题搁置了好多天(准确来说是忘记了)。

3月8号再次修改这篇文章的时候,正好看到了 MiniCssExtractPlugin.loader 对应的 option 设置,我们再次修改下对应的 rule

module.exports = { rules: [ { test: /\.(c|le)ss$/ use: [ { loader: MiniCssExtractPlugin.loader options: { hmr: isDev reloadAll: true } } //... ] exclude: /node_modules/ } ] }

webpack 详细教程:带你深度解读Webpack系列 进阶篇(4)

4.按需加载


很多时候我们不需要一次性加载所有的JS文件,而应该在不同阶段去加载所需要的代码。webpack 内置了强大的分割代码的功能可以实现按需加载。

比如,我们在点击了某个按钮之后,才需要使用对应的JS文件中的代码,需要使用 import() 语法:

document.getElementById('btn').onclick = function() { import('./handle').then(fn => fn.default()); }

import() 语法,需要 @babel/plugin-syntax-dynamic-import 的插件支持,但是因为当前 @babel/preset-env 预设中已经包含了 @babel/plugin-syntax-dynamic-import,因此我们不需要再单独安装和配置。

直接 npm run build 进行构建,构建结果如下:

webpack 详细教程:带你深度解读Webpack系列 进阶篇(5)

猜您喜欢: