最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 从零到一学会webpack 03-缓存

    正文概述 掘金(_膨胀的大雄_)   2021-02-28   436

    这一篇主要讲缓存,内容基本与webpack的文档部分-指南-缓存保持一致~已经了解过的同学不必要再看了

    是的,上面这段文字,我是直接复制的官网~

    看前面两篇文章应该已经看到了,我在output配置中,已经使用了如下表示:

      output: {
        path: path.resolve(__dirname, "dist/"),
        filename: "[name].bundle.js"
      },
    

    这里的[name] 我们称之为:substitutions --- 也就是一个占位符,执行build后被会替换。

    在客户端向服务端请求资源时候,对应的资源匹配符一般是 url/path/filename,因此,当filename不发生变化时候,客户端会命中缓存,当我们文件发生修改,构建后的文件名字就需要更改,这样客户端就不会使用缓存文件,我们回到最简单的代码和配置。

    ├── dist
    ├── public
    │   └── index.html
    ├── src
    │   ├── App.css
    │   ├── App.jsx
    │   └── index.js
    ├── webpack.config.js
    ├── package.json
    └── yarn.lock
    ├── .babelrc
    

    webpack.config.js

    const path = require("path");
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    
    
    module.exports = {
      entry: "./src/index.js",
      output: {
        path: path.resolve(__dirname, "dist/"),
        filename: "index.js"
      },
      module: {
        rules: [
          {
            test: /\.(js|jsx)$/,
            exclude: /(node_modules|bower_components)/,
            loader: "babel-loader",
            options: { presets: ["@babel/env"] }
          },
          {
            test: /\.css$/,
            use: ["style-loader", "css-loader"]
          }
        ]
      },
      resolve: { extensions: ["*", ".js", ".jsx"] },
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          title: '缓存',
          template: './public/index.html'
        }),
      ]
    };
    

    以上对于单入口的配置,会生成固定的fimename为index.js的文件,但是通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个 bundle,应该使用以下一种替换方式,来赋予每个 bundle 一个唯一的名称

    设置output filename

    1. 使用入口名称:
    module.exports = {
      //...
      output: {
        filename: '[name].bundle.js',
      },
    };
    
    1. 使用内部 chunk id
    module.exports = {
      //...
      output: {
        filename: '[id].bundle.js',
      },
    };
    
    1. 使用由生成的内容产生的 hash:
    module.exports = {
      //...
      output: {
        filename: '[contenthash].bundle.js',
      },
    };
    
    1. 结合多个替换组合使用:
    module.exports = {
      //...
      output: {
        filename: '[name].[contenthash].bundle.js',
      },
    };
    
    1. 使用函数返回 filename:
    module.exports = {
      //...
      output: {
        filename: (pathData) => {
          return pathData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js';
        },
      },
    };
    

    更复杂和更高级的用法,参见webpack的文档:outputfilename

    你可以简单地对以上四种方式进行设置看看build后结果。

    这里我们设置为:

    module.exports={
        //...
        output: {
        path: path.resolve(__dirname, "dist/"),
        filename: "[name].[contenthash].js"
      },
    }
    

    build后输出结果为:

    ├── index.html
    ├── main.2a5c2d475953a2c073fc.js
    └── main.2a5c2d475953a2c073fc.js.LICENSE.txt // 不用管
    

    可以看到,生成的文件名是根据我们配置的方式产生的

    提取引导模板(extracting boilerplate)

    webpack 还提供了一个优化功能,可使用 optimization.runtimeChunk 选项将 runtime 代码拆分为一个单独的 chunk。将其设置为 single 来为所有 chunk 创建一个 runtime bundle

    const path = require("path");
    const webpack = require("webpack");
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    // const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
    
    module.exports = {
      entry: "./src/index.js",
      output: {
        path: path.resolve(__dirname, "dist/"),
        filename: "[name].[contenthash].js"
      },
      module: {
        rules: [
          {
            test: /\.(js|jsx)$/,
            exclude: /(node_modules|bower_components)/,
            loader: "babel-loader",
            options: { presets: ["@babel/env"] }
          },
          {
            test: /\.css$/,
            use: ["style-loader", "css-loader"]
          }
        ]
      },
      resolve: { extensions: ["*", ".js", ".jsx"] },
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          title: '管理输出',
          template: './public/index.html'
        }),
      ],
      optimization: {
        runtimeChunk: 'single',
      },
    };
    

    build后文件为:

    ├── index.html
    ├── main.e015ebc8a50a50e241af.js
    ├── main.e015ebc8a50a50e241af.js.LICENSE.txt
    └── runtime.fb3fdb31b8fba3a87894.js
    

    可以看到,新生成了一个runtime.fb3fdb31b8fba3a87894.js文件。

    我们继续:将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用 client 的长效缓存机制,命中缓存来消除请求,并减少向 server 获取资源,同时还能保证 client 代码和 server 代码版本一致,这可以通过使用 SplitChunksPlugin 示例 2 中演示的 SplitChunksPlugin 插件的 cacheGroups 选项来实现

        // ...
        optimization: {
            runtimeChunk: 'single',
            splitChunks: {
            cacheGroups: {
            vendor: {
               test: /[\\/]node_modules[\\/]/,
               name: 'vendors',
               chunks: 'all',
             },
           },
         },
        },
    

    生成的代码文件为,仔细看看main的代码大小:main中不包含任何依赖相关代码了

    ├── index.html
    ├── main.7f74a4145b9a5f89c983.js
    ├── runtime.fb3fdb31b8fba3a87894.js
    ├── vendors.60580f0863c3f8e70856.js
    └── vendors.60580f0863c3f8e70856.js.LICENSE.txt
    

    接下来,我们再src目录新增一个print.js

    export function print() {
      console.log('print!!!')
    }
    

    再App.jsx中引入print方法并执行

    import React from "react";
    import print from './print';
    import "./App.css";
    
    function App() {
      print();
      return (
        <div className="App">
          <h1> Hello, World </h1>
        </div>
      );
    }
    export default App;
    

    build后生成的文件:

    ├── index.html
    ├── main.ecda747780e86fe47ecf.js
    ├── runtime.b8a0cf32c66c8e3d96c6.js
    ├── vendors.ed2678b03f97207cadab.js
    └── vendors.ed2678b03f97207cadab.js.LICENSE.txt
    

    我们期望的是main的filename发生修改:因为我们修改的只是打包进入main文件的代码,但是事实上发现,生成的所有文件名都发生了修改~

    这是因为每个 module.id 会默认地基于解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变。因此,简要概括:

    main bundle 会随着自身的新增内容的修改,而发生变化。 vendor bundle 会随着自身的 module.id 的变化,而发生变化。 manifest runtime 会因为现在包含一个新模块的引用,而发生变化。 第一个和最后一个都是符合预期的行为,vendor hash 发生变化是我们要修复的。我们将 optimization.moduleIds 设置为 'deterministic':

      optimization: {
        runtimeChunk: 'single',
        moduleIds: 'deterministic',
        splitChunks: {
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name: 'vendors',
              chunks: 'all',
            },
          },
        },
      },
    

    再次执行build一次、再删除print.js和print相关代码,会发现,vendor hashd都没有发生变化


    起源地下载网 » 从零到一学会webpack 03-缓存

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元