05-webpack核心基础-plugin

2020-04-12  本文已影响0人  仰望_IT

什么是插件(plugin)?


plugin 用于扩展webpack的功能。
当然loader也是变相的扩展了webpack ,但是它只专注于转化文件这一个领域。而plugin的功能更加的丰富,而不仅局限于资源的加载。在 webpack 的构建流程中,plugin 用于处理更多其他的一些构建任务。可以这么理解,模块代码转换的工作由 loader 来处理,除此之外的其他任何工作都可以交由 plugin 来完成。

如何使用插件


1. 安装需要的插件

例如:
安装HtmlWebpackPlugin

npm install --save-dev html-webpack-plugin
2. 配置对应的插件

webpack.config.js

// 导入对应的插件
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    plugins: [new HtmlWebpackPlugin()]
}

webpack常用的plugin


1. HtmlWebpackPlugin

HtmlWebpackPlugin
HtmlWebpackPlugin会在打包结束之后自动创建一个index.html, 并将打包好的JS自动引入到这个文件中

npm install --save-dev html-webpack-plugin
// 导入HtmlWebpackPlugin插件
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    plugins: [new HtmlWebpackPlugin()]
}

更多高级配置请查看 插件文档

2. CleanWebpackPlugin

webpack-clean-plugin会在打包之前将我们指定的文件夹清空
应用场景:每次打包前将dist目录清空, 然后再存放新打包的内容, 避免新老混淆问题
参考文档

npm install --save-dev clean-webpack-plugin
// 导入CleanWebpackPlugin插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    plugins: [new CleanWebpackPlugin()]
}
3. CopyWebpackPlugin

在打包项目的时候除了JS/CSS/图片/字体图标等需要打包以外, 可能还有一些相关的文档也需要打包
文档内容是固定不变的, 我们只需要将对应的文件拷贝到打包目录中即可, 那么这个时候我们就可以使用copy-plugin来实现文件的拷贝
参考文档

npm install --save-dev copy-webpack-plugin
// 导入CleanWebpackPlugin插件
const CopyWebpackPlugin = require('CopyWebpackPlugin');

module.exports = {
    plugins: [
        new CopyWebpackPlugin([
            // 从哪个文件拷贝到哪个文件
            {from:"doc", to:"./doc"}
        ])
    ]
}
4. MiniCssExtractPlugin

mini-css-extract-plugin是一个专门用于将打包的CSS内容提取到单独文件的插件

前面我们通过style-loader打包的CSS都是直接插入到head中的

参考文档

npm install --save-dev mini-css-extract-plugin
// 导入 MiniCssExtractPlugin 插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    plugins: [
        new MiniCssExtractPlugin({
            filename: './css/[name].css',
      })
    ]
}
module.exports = {
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

因为style-loader的作用是将webpack处理之后的内容插入到HTML的HEAD代码中, 现在我们是需要打包到一个单独的文件中

【注意】
如果相关文件资源无法显示, 需要根据打包后的结构手动设置公开路径
webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../',
            },
          },
          'css-loader',
        ],
      },
    ],
  },
};
|---bundle
       |---css
            |---index.css
       |---js
            |---index.js
       |---images
            |---animal.jpg
       |---index.html

解决方案
在开发阶段将publicPath设置为dev-server服务器地址
在上线阶段将publicPath设置为线上服务器地址

5. 压缩CSS代码( OptimizeCSSAssetsPlugin 和 TerserJSPlugin )

压缩用mini-css-extract-plugin插件打包的css代码
参考文档
参考文档

npm install --save-dev optimize-css-assets-webpack-plugin
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
    // optimization: 配置webpack的优化项
    optimization: {
        minimizer: [new OptimizeCSSAssetsPlugin({})],
    },
}

注意
由于配置了webpack的optimization.minimizer项目会覆盖默认的JS压缩选项, 所以JS代码也需要通过插件自己压缩

npm install --save-dev terser-webpack-plugin
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');

module.exports = {
    // optimization: 配置webpack的优化项
    optimization: {
        minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
    },
    // mode: 指定打包的模式, 
    // production: 上线(生产)模式, 会对打包的JS代码进行压缩
    mode: "production",
}
6. 监听打包文件变化( watch 和 devServer)
module.exports = {
    // 监听打包文件变化,当它们修改后会重新编译打包
    watch: true,
    watchOptions: {
        aggregateTimeout: 300,  // 防抖, 和函数防抖一样, 改变过程中不重新打包, 只有改变完成指定时间后才打包
        poll: 1000,  // 每隔多少时间(毫秒)检查一次变动
        ignored: /node_modules/  // 排除一些巨大的文件夹, 不需要监控的文件夹
    },
}
npm install webpack-dev-server --save-dev
module.exports = {
    devServer: {
        // 告诉devServer要把哪个目录运行在服务器环境下
        contentBase: "./bundle",
        // 编译打包之后是否需要自动在浏览器中打开, 默认为false.
        // 如果为false则需要自己在浏览器地址栏输入localhost:8080
        open: true,
        // 端口号, 默认是8080
        port: 9090
    },
}

打包指令由原来的npx webpack更改为npx webpack-dev-server

webpack.config.js

module.exports = {
    devServer: {
        contentBase: "./bundle",
        open: true,
        port: 9090,
        proxy: [{
            context: ["/user", "/login"],
            /*
            target: 当我们在代码中发送请求到/user的时候, devServer就会自动将我们请求的地址替换为
            http://127.0.0.1:3000/user
            */
            target: "http://127.0.0.1:3000",
            changeOrigin: true,     // 域名跨域
            secure: false,          // https跨域
            pathRewrite:{"": "/api"} // 路径重写, 将路径中的api替换为空
        }]
    }
}

【注意】
devServer只能解决开发阶段的跨域问题, 并不能解决项目上线之后的跨域问题
因为项目上线之后是将打包好的文件上传到服务器, 而打包好的文件中并没有devServer, 所以项目上线之后要想解决跨域问题还是需要依赖后端开发人员
通过webpack-dev-server自动打包并没有真正的放到指定的目录中, 因为读写磁盘是非常耗时和消耗性能的, 所以为了提升性能webpack-dev-server将转换好的内容直接放到了内存中

常用配置附录

  • target:要使用url模块解析的url字符串
  • forward:要使用url模块解析的url字符串
  • agent:要传递给http(s).request的对象(请参阅Node的https代理和http代理对象)
  • ssl:要传递给https.createServer()的对象
  • ws:true / false,是否代理websockets
  • xfwd:true / false,添加x-forward标头
  • secure:true / false,是否验证SSL Certs
  • toProxy:true / false,传递绝对URL作为路径(对代理代理很有用)
  • prependPath:true / false,默认值:true - 指定是否要将目标的路径添加到代理路径
  • ignorePath:true / false,默认值:false - 指定是否要忽略传入请求的代理路径(注意:如果需要,您必须附加/手动)。
  • localAddress:要为传出连接绑定的本地接口字符串
  • changeOrigin:true / false,默认值:false - 将主机标头的原点更改为目标URL
7. HotModuleReplacementPlugin

通过webpack-dev-server可以实现实时监听打包内容的变化, 每次打包之后都会自动刷新网页, 但是正是因为每当内容被修改时都会自动刷新网页, 所以给我们带来了很多不便, 这时就需要通过HMR插件来优化调试开发

HMR(HotModuleReplacementPlugin)热更新插件, 在内容发生改变的时候时时的更新修改的内容但是不会重新刷新网站

const webpack = require("webpack");

module.exports = {
    devServer: {
        hot: true, // 开启热更新, 只要开启了热更新就不会自动刷新网页了
        hotOnly: true // 哪怕不支持热更新也不要刷新网页
    },
    plugins: [
          new webpack.HotModuleReplacementPlugin()
    ]
}

【注意】
如果是通过style-loader来处理CSS, 那么经过前面两步就已经实现了热更新
如果是通过MiniCssExtractPlugin.loader来处理CSS, 那么还需要额外配置MiniCssExtractPlugin.loader

loader: MiniCssExtractPlugin.loader,
options:{
    hmr: true
}
// 判断当前有没有开启热更新
if (module.hot){
    // 告诉热更新需要监听哪一个JS模块的变化
    module.hot.accept("./test.js", function () {
          // 手动编写模块变化后的业务逻辑
    });
} 
8. babel

在开发中为了兼容一些低级版本的浏览器, 我们需要将ES678高级语法转换为ES5低级语法, 否则在低级版本浏览器中我们的程序无法正确执行。默认情况下webpack是不会将我们的代码转换成ES5低级语法的, 如果需要转换我们需要使用babel来转换
参考文档

npm install --save-dev babel-loader @babel/core  @babel/preset-env
module: {
  rules: [
        {
            test: /\.js$/,
            exclude: /node_modules/,  // 不做处理的目录
            loader: "babel-loader",
            options: {
                presets: ["@babel/preset-env"],
            },
        }
  ]
}
"presets": [["@babel/preset-env",{
    targets: {
        "chrome": "58",
        "ie": "10"
    },
}]],

利用babel实现低版本语法
对于有对应关系的语法而言, 经过我们上面的配置就已经能够实现自动转换了,但是对于没有对应关系的语法而言, 经过我们上节面的配置还不能实现自动转换。
什么叫有对应关系, 什么叫做没有对应关系?
有对应关系就是指ES5中有对应的概念, 例如: 箭头函数对应普通函数, let对应var, 这个就叫做有对应关系
没有对应关系就是指E5中根本就没有对应的语法, 例如Promise, includes等方法是ES678新增的,ES5中根本就没有对应的实现, 这个时候就需要再增加一些额外配置, 让babel自己帮我们实现对应的语法
参考文档

npm install --save @babel/polyfill
import "@babel/polyfill";

Promise.resolve().then(function () {
    console.log("babel");
});

注意
如果导入了polyfill,那么无论我们有没有用到没有对应关系的语法都会打包到文件中。但是这样会增加打包后文件的大小, 我们希望的是只将用到的不存在对应关系的语法打包到文件中,那么就需要在webpack.config.js中再配置一下。

"presets": [["@babel/preset-env",{
    ...
    // 只打包没有对应关系的语法
    useBuiltIns: "usage"
}]],

如果设置了useBuiltIns: "usage属性, 那么polyfill会自动引入, 不需要我们再手动导入

babel 的第二种配置方式
直接导入polyfill的方式只适用于一般项目开发, 但是如果是在编写一些第三方模块的时候这种方式会出现一些问题。因为这种方式是通过全局变量的方式来注入代码, 会污染全局环境. 所以我们再来看一下polyfill的第二种配置方式
参考文档

npm install --save @babel/polyfill
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
{
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "absoluteRuntime": false,
        "corejs": 2,
        "helpers": true,
        "regenerator": true,
        "useESModules": false,
        "version": "7.0.0-beta.0"
      }
    ]
  ]
}

注意
"corejs": false, 还是全局注入,还是会污染全局环境
"corejs": 2, 则不会污染全局环境, 所以还需要安装corejs2

npm install --save @babel/runtime-corejs2

babel-使用技巧

  1. 查看错误信息
  2. 根据错误信息查询 文档
  3. 根据文档缺什么安装配置什么
9. webpack-merge

为了便于维护配置文件, 我们会将开发阶段、上线阶段、公共配置分为三个文件。
webpack-merge模块就是用来实现重复代码的抽离和合并进一步优化配置文件。

npm install --save-dev webpack-merge
上一篇 下一篇

猜你喜欢

热点阅读