美文网首页
Webpack 5 新特性尝鲜

Webpack 5 新特性尝鲜

作者: 西岭老湿 | 来源:发表于2021-02-03 17:08 被阅读0次

    安装与启动

    Webpack 5 发布已经有一段时间了,很多小伙伴都在考虑要不要升级,有没有升级的必要,不知道升级后有哪些改变;
    今天我们就来做个对比看看,webpack5 带来了那些全新的改变;
    没有对比就没有伤害,为了更好地伤害 webpack 4 , 我们使用 webpack4 和 webpack 5 分别构建一个 React 项目来做对比:

    mkdir webpack4 
    mkdir webpack5 
    # 分别执行 初始化命令 
    npm init -y 
    

    创建文件 /src/index.js, /src/App.js, /src/index.html

    React 代码示例

    index.js

    import React from "react"
    import ReactDom from "react-dom"
    import App from "./App"
    ReactDom.render(<App/>,document.getElementById('root'))
    

    App.js

    import React from "react"
    const App = ()=>{
      return (
          <div>
            <h1> Webpack4 or Webpack5 </h1>
          </div>
      )
    }
    export default App;
    

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <!-- 加一行注释 -->
      <div id="root"></div>
    </body>
    </html>
    
    安装与启动
    webpack4
    // webpack4 
    npm install webpack@4 webpack-cli@3  html-webpack-plugin css-loader style-loader babel-loader @babel/core  @babel/preset-env  @babel/preset-react  -D 
    npm install react react-dom 
    

    因为仓库中目前默认就已经是 webpack5 了,所以,想要安装 webpack4, 我们需要加上 @4 的版本号;

    webpack5
    // webpack5 
    npm install webpack webpack-cli html-webpack-plugin css-loader style-loader babel-loader @babel/core  @babel/preset-env  @babel/preset-react  -D 
    npm install react react-dom 
    
    基础配置 webpack.config.js
    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
      // entry 入口,output出口,module模块,plugins 插件  mode工作模式,devServer开发服务器
      //  mode 工作模式
      mode: 'development', // production  、 development、none
      // 入口 
      entry:'./src/index.js',
      //  出口 
      output:{
        filename:'./bundle.js',
        path:path.resolve(__dirname,'dist')
      },
      // 模块 
      module:{
        rules:[
          {
            test:/\.js$/,
            exclude:/node_modules/,
            use:[
              {
                loader:'babel-loader',
                options:{
                  presets:[
                    '@babel/preset-env',
                    '@babel/preset-react'
                  ]
                }
              }
            ]
          },
        ]
      },
      //  插件 
      plugins:[
        new HtmlWebpackPlugin({
          template:'./src/index.html'
        })
      ]
    }
    

    启动命令的区别

    先安装 npm install webpack-dev-server -D
    配置服务器:

    //  服务器
      devServer:{
        port:3004,
        open:true
      },
    

    webpack 4 : webpack4/package.json

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack",
        "start": "webpack-dev-server"
      },
    

    webpack 5 : webpack5/package.json

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build":"webpack",
        "start":"webpack serve"
      },
    

    资源模块处理

    https://webpack.docschina.org/guides/asset-modules/#source-assets
    资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。
    在 webpack 5 之前,通常使用:

    资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:

    • asset/resource 发送一个单独的文件并导出 URL(之前通过使用 file-loader 实现)
    • asset/inline 导出一个资源的 data UR(之前通过使用 url-loader 实现)
    • asset/source 导出资源的源代码(之前通过使用 raw-loader 实现)
    • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择(之前通过使用 url-loader,并且配置资源体积限制实现)

    webpack4 :

    // 模块 
      module:{
        rules:[
          {
            test:/\.js$/,
            exclude:/node_modules/,
            use:[
                …………
            ]
          },
          {
            test:/\.(png|jpg|gif)$/,
            // 安装 url-loader  file-loader 
            loader:'url-loader',
            options:{
              // 小于 8KB 转 base64 
              limit:8*1024
            }
          }
        ]
      },
    

    webpack5 :

    // 模块 
      module:{
        rules:[
          {
            test:/\.js$/,
            exclude:/node_modules/,
            ……………………
          },
          {
            test:/\.(png|jpg|gif)$/,
            // 通用资源类型
            type:'asset',
            // 现在,webpack 将按照默认条件,自动地在 resource 和 inline 之间进行选择:
            // 小于 8kb 的文件,将会视为 inline 模块类型,否则会被视为 resource 模块类型。
            // 自定义设置
            parser:{
              dataUrlCondition:{
                maxSize:8*1024
              }
            }
          }
        ]
      },
    

    文件缓存

    https://webpack.docschina.org/configuration/other-options/#cache
    缓存生成的 webpack 模块和 chunk,能够改善构建速度。
    cache 会在 开发模式 下被设置成 type: 'memory' 而且在 生产模式 中被禁用。
    cache: true 与 cache: { type: 'memory' } 配置作用一致。

    cache.type

    cache.type 将 cache 类型设置成内存或者文件系统。 'memory' | 'filesystem'
    memory 选项很简单,它会告诉 webpack 将内容存放在内存中并且不允许额外的配置;
    filesystem 选项,使用文件缓存系统;

    cacheDirectory

    cacheDirectory 定义缓存目录, 默认为 node_modules/.cache/webpack。

    cache.cacheDirectory 选项仅当 cache.type 被设置成 filesystem 才可用。

    webpack.config.js

      //  mode 工作模式
      mode:'development',
      cache:{
        type:'filesystem',
        // 默认缓存到 node_modules/.cache/webpack 中 
        // 也可以自定义缓存目录
        // cacheDirectory:path.resolve(__dirname,'node_modules/.cac/webpack')
      }
    
    image-20210121211424446.png

    即使内容修改,增量编译的缓存效果也很明显

    更好的 Tree Shaking

    https://webpack.docschina.org/guides/tree-shaking/
    Tree Shaking 技术,也被称为 “树摇” ,没错,翻译的就是这么直接,意思也很简单,未使用的导出内容不会被打包生成;它依赖于 ES2015 模块语法的 静态结构 特性,例如 importexport。这个术语和概念实际上是由 ES2015 模块打包工具 rollup 普及起来的。

    为了更好说明这个原理,我做了一个动画,全网首发的动画效果,简单解释一下,有两个模块四个方法,在模块 x 中,使用了 B 方法和从模块Y中导入的 C 方法,而 X 模块中自己的 A 和模块 Y 中的 D 方法,并没有使用,虽然定义了,因为没有在任何地方使用过,因此,在 “摇树” 过程中,就会被 “摇掉”;

    Snipaste_2021-01-20_14-00-99.gif

    在 webpack 中如何使用呢?其实很简单,只要将 mode 工作模式改为 production 就会自动开启;
    而如果想要感受这个树摇带来的震动酥麻酸爽的过程,我们也可以使用手动配置的方式来自行选择,首先需要将 mode 工作模式改为 none,意思就是不做任何优化,全部使用配置的方式,如何配置呢?添加 optimization.usedExports 和 optimization.minimize 选项,意思就是开启树摇及压缩

    //  mode 工作模式
      mode: 'none', // production、development、none
      // production 生产环境,默认优化打包
      // none 不做任何操作
    
      // usedExports:true 开启优化(树摇但保留代码)
      // minimize:true 开启压缩 (删除未使用代码)
      optimization:{
        usedExports:true,
        minimize:true
        // innerGraph: true,
      }
    

    接下来,我们再使用简单代码做对比:
    index.js

    import * as m1 from "./m1";
    console.log(m1.m2.nu1)
    

    m1.js

    import * as m2 from './m2'
    export function fun1(){
      console.log('1--11',m2.c);
    }
    export function fun2(){
      console.log('1--22')
    }
    export {m2}
    

    m2.js

    export function fun3(){
      console.log('2--33');
    }
    export function fun4(){
      console.log('2--44')
    }
    export const nu1 = 456
    export const nu2 = 789
    
    image-20210121213316812.png

    相同的代码,在webpack 4 的打包结果中,我们能看到不仅代码量大,而且还有 i=789 这个多余的代码,反观 webpack 5 的打包结果,简洁到难以置信;

    模块联邦

    多个独立的构建可以组成一个应用程序,这些独立的构建之间不应该存在依赖关系,因此可以单独开发和部署它们。
    这通常被称作微前端
    为了更好地说明这个原理,我做了一个动画,全球首发的动画效果

    Snipaste_2021-01-20_14-0099.gif
    // ======insex.js========
    import React from "react"
    import ReactDom from "react-dom"
    import App from "./App"
    ReactDom.render(<App/>,document.getElementById('root'))
    // ======App.js===========
    import React from "react"
    import User from "./User"
    let App = () => {
        return (
            <div>
                <h3>webpack55</h3>
                <User/>
            </div>
        )
    }
    export default App;
    // ===== User.js==========
    import React from "react"
    
    const User = ()=>{
      return (
        <div>
          UserList
        </div>
      )
    }
    export default User
    
    导出模块
    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    // const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin")
    const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin;
    …………
      //  插件 
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html'
        }),
        new ModuleFederationPlugin({
          // 模块名字
          name: 'remote', //导入时使用名称标注
          // 编译后的模块文件名,导入时使用
          filename: 'remoteEntry.js',
          // 导出模块 关键字与模块名
          exposes: {
            // "key导入时使用的关键字" : "对应模块文件"
            "./Us": './src/User.js'
          }
        }),
      ],
    
    导入模块
    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin;
    
    …………
    
      //  插件 
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html'
        }),
        new ModuleFederationPlugin({
          name:'user:55',
          // 导入外部模块
          remotes:{
            // 导入别名:关键字@地址/导出文件名
            remoteHost:"remote@http://127.0.0.1:3055/remoteEntry.js"
          }
        })
      ],
    
    import React from "react"
    // React.lazy(() => import("对应导入别名/对应导出关键字"))
    const Us = React.lazy(() => import("remoteHost/Us"))
    
    let App = () => {
        return (
            <div>
                <h3>hello web webpack 5</h3>
                <p>联邦模块 webpack5 </p>
                {/* 展示导入模块内容 异步加载 */}
                <React.Suspense fallback="Loading app">
                    <Us />
                </React.Suspense>
            </div>
        )
    }
    export default App;
    

    在 ModuleFederationPlugin 实例化的时候传入参数 options 的字段说明:

    // 模块名字
    name: 'remote', //导入时使用名称标注
    // 编译后的模块文件名,导入时使用
    filename: 'remoteEntry.js',
    // 导出模块 关键字与模块名
    exposes: {
        // "key导入时使用的关键字" : "对应模块文件"
        "./Us": './src/User.js'
    }
     // 导入外部模块
    remotes:{
       // 导入别名:关键字@地址/导出文件名
       remoteHost:"remote@http://127.0.0.1:3055/remoteEntry.js"
    }
    

    还有就是 exposes 和 remotes 的字段小伙伴们也要注意,
    exposes 的暴露字段要写上 ./name
    remotes 的字段跟暴露模块的 name 保持一致,里面别名的定义也要一致
    最后,两个应用同时启动,就会发现最终你要的应用就把其他应用的模块也引入进来了

    相关文章

      网友评论

          本文标题:Webpack 5 新特性尝鲜

          本文链接:https://www.haomeiwen.com/subject/oppptltx.html