webpack生产模式“构建”-强制浏览器不读取缓存文件/重新构建新文件

oogrdqng  于 2023-01-30  发布在  Webpack
关注(0)|答案(2)|浏览(136)

我们有一个应用程序(一个网站)与一些React组件,css和js编译与webpack。
我们的工作流程是在本地开发的时候在/src/文件夹中创建npm run start,在/dist/中生成CSS和JS文件,然后运行npm run build来清除刷新/dist/文件夹中的所有文件,然后再部署到live。
问题是,当我们将一个变更部署到实时环境中时,浏览器似乎仍然缓存了以前版本的CSS/JS文件,或者没有正确阅读新版本的文件。这种情况只发生在散列/分块(React组件)文件(见下面文件结构中的**),而不是main.js或main.scss文件。
我们认为webpack在每次构建时都会生成新的“chunks”/文件。是否有办法强制webpack这样做,以便在文件更改时读取为新文件,或者文件名不同?我确实希望浏览器缓存这些文件,但我也希望考虑到新的更改。

示例文件结构

--/src/
----/scss/
------main.scss
----/js/
------main.js (imports js components)
------/components/
--------banner.js
--------ReactComponent.jsx (imports ReactComponent.scss)
--------ReactComponent.scss
--/dist/
----/css/
------main.css
------2.css (react component css) (**)
------6.css (react component css) (**)
----/js/
------main.js
------0_39cd0323ec029f4edc2f.js (react component js) (**)
------1_c03b31c54dc165cb590e.js (react component js) (**)

**这些文件似乎被缓存或在进行更改时无法正确读取。
网络包配置js

const webpack = require("webpack");
const path = require("path");
const autoprefixer = require("autoprefixer");
const TerserJSPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
  entry: {
    main: ["./js/main.js", "./scss/main.scss"],
  },
  output: {
    filename: "js/[name].js",
    chunkFilename: "js/[name]_[chunkhash].js",
    path: path.resolve(__dirname, "../dist/"),
    publicPath: "/app/themes/[package]/dist/",
    jsonpFunction: "o3iv79tz90732goag"
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules)/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.(sass|scss|css)$/,
        exclude: "/node_modules/",
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              importLoaders: 2,
              sourceMap: true
            }
          },
          {
            loader: "postcss-loader",
            options: {
              plugins: () => [require("precss"), require("autoprefixer")],
              sourceMap: true
            }
          },
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
              includePaths: [path.resolve(__dirname, "../src/scss")]
            }
          }
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ["file-loader"]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: ["file-loader"]
      }
    ]
  },
  optimization: {
    minimizer: [
      new TerserJSPlugin({
        cache: true,
        parallel: true,
        sourceMap: true
      }),
      new OptimizeCSSAssetsPlugin({
        cssProcessorOptions: {
          safe: true,
          zindex: false,
          discardComments: {
            removeAll: true
          }
        },
        canPrint: true
      })
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name].css",
      chunkFilename: "css/[id].css"
    })
  ]
};

包.json

{
        "name": "packagename",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1",
            "build": "(rm -rf ./../dist/*) & webpack --mode production",
            "start": "webpack --mode development --watch "
        },
        "keywords": [],
        "author": "Sarah",
        "license": "ISC",
        "browserslist": [
            "last 4 versions"
        ],
        "devDependencies": {
            "@babel/core": "^7.9.0",
            "@babel/plugin-proposal-object-rest-spread": "^7.9.5",
            "@babel/plugin-syntax-dynamic-import": "^7.8.3",
            "@babel/plugin-transform-arrow-functions": "^7.2.0",
            "@babel/plugin-transform-classes": "^7.9.5",
            "@babel/plugin-transform-flow-strip-types": "^7.9.0",
            "@babel/plugin-transform-react-jsx": "^7.9.4",
            "@babel/preset-env": "^7.9.5",
            "@babel/preset-flow": "^7.9.0",
            "@babel/preset-react": "^7.0.0",
            "autoprefixer": "^7.1.1",
            "babel-loader": "^8.1.0",
            "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
            "babel-preset-env": "^1.7.0",
            "browser-sync": "^2.26.7",
            "browser-sync-webpack-plugin": "^2.2",
            "copy-webpack-plugin": "^4.0.1",
            "css-loader": "^3.5.3",
            "cssnano": "^4.1.10",
            "mini-css-extract-plugin": "^0.8.2",
            "node-sass": "^4.14.0",
            "optimize-css-assets-webpack-plugin": "^5.0.3",
            "postcss-loader": "^2.0.5",
            "precss": "^4.0.0",
            "resolve-url-loader": "^2.0.2",
            "sass-loader": "^6.0.5",
            "terser-webpack-plugin": "^2.3.6",
            "webpack": "^4.43.0",
            "webpack-cli": "^3.3.11"
        },
        "dependencies": {
            "axios": "^0.19.2",
            "body-scroll-lock": "^2.7.1",
            "can-autoplay": "^3.0.0",
            "debounce": "^1.0.2",
            "file-loader": "^5.1.0",
            "lazysizes": "^4.1.8",
            "moment": "^2.24.0",
            "objectFitPolyfill": "^2.3.0",
            "promise-polyfill": "^8.1.3",
            "react": "^16.9.0",
            "react-content-loader": "^5.0.4",
            "react-device-detect": "^1.12.1",
            "react-dom": "^16.9.0",
            "react-html-parser": "^2.0.2",
            "react-intersection-observer": "^8.26.2",
            "react-moment": "^0.9.7",
            "react-pdf": "^4.1.0",
            "scrollmonitor": "^1.2.4",
            "socket.io": "^2.3.0"
        }
    }
vuktfyat

vuktfyat1#

为了在构建时破坏缓存,您需要更改静态资产(js / css)的url。
最好的方法是根据文件的内容生成随机字符串(称为哈希),这种方法的好处是,如果最终文件在两次部署之间没有改变,它将生成相同的哈希=〉客户端将使用缓存的文件。如果最终文件改变了=〉哈希改变=〉文件名改变=〉客户端将获取一个新文件。
Webpack有一个内置的方法。

// webpack.config.js

module.exports = {
  entry: {
    main: ["./js/main.js", "./scss/main.scss"],
  },
  output: {
    filename: process.env.NODE_ENV === 'production'? "js/[name]-[hash].js": "js/[name].js", // this will attach the hash of the asset to the filename when building for production
    chunkFilename: "js/[name]_[chunkhash].js",
    path: path.resolve(__dirname, "../dist/"),
    publicPath: "/app/themes/[package]/dist/",
    jsonpFunction: "o3iv79tz90732goag"
  },
  ...
}

编辑:为了用新的文件名(现在将包含哈希)更新HTML文件,您可以使用专门为此创建的HTMLWebpackPlugin
它支持自定义模板,如果你需要提供自己的html,或创建一个。查看文档。

apeeds0o

apeeds0o2#

只是对brilliant @felixmosh解决方案的一个小更新。
对于Webpack 5.x,我使用以下代码:

//webpack.prod.js

const webpackConfig = {
  module: {
    ...
  },
  output: {
    filename: '[name]-[contenthash].js', 
    chunkFilename: '[name]_[contenthash].js',
  },

[contenthash]看起来比[hash]更好- contenthash只在资产的内容实际发生变化时才发生变化,我想知道为什么这不是Webpack的默认设置?
我爱你们这些家伙“felixmosh”莎拉想出了这个办法!

相关问题