首页 > 解决方案 > 通过 Webpack 创建带有哈希的供应商包并在同构应用程序中使用它

问题描述

我有三种不同的 Webpack 配置(client.webpack.js、server.webpack.js 和 vendor.webpack.js) vendor.webpack.js 用于创建供应商包,因为它们很少更改并且占用大量空间。我们使用DllPlugin它来生成它,并通过在 client.webpack.js 中使用生成的 manifest.json DllReferencePlugin

我想做的改进是向供应商文件添加一个哈希,例如,我想创建 vendor.348723.js,而不是 vendor.js。这样做的原因是为了改进缓存。

棘手的部分是我们的应用程序是同构的,这意味着 HTML 的生成是由服务器(Node.js + React,server.webpack.js)在运行时完成的。在服务器内部,在一个 JS 文件中,我们创建了模板,并且在<script type='text/javascript' src='/vendor.js'></script>某个地方。我的问题是,我如何在那里注入 vendor.SOMEHASH.js ?

我尝试过但失败了:

扩展API插件

使用 React.js 使用 Webpack 缓存,索引源代码中的 [hash] 值

在 vendor.webpack.js 中使用 ExtendedAPIPlugin,并尝试使用__webpack_hash__在 vendor.webpack.js 中使用 ExtendedAPIPlugin,并在生成 HTML 模板时<script type='text/javascript' src='/vendor.${__webpack_hash__}.js'></script>,例如, 由于我有两个不同的 Webpack 配置,并且我在 vendor.webpack.js 中生成哈希,服务器无法识别它生成 HTML 模板时。

其他相关信息

我们不使用 html-webpack-plugin——我认为它不适用,因为我们有一个同构的应用程序。( Webpack - 更新 HTML 以包含最新的 [hashed] 包的最佳方式

我看过的其他相关页面

在提取文本插件之后将带有哈希的 css 文件名链接到 index.html

vendor.webpack.js

const path = require('path')
const webpack = require('webpack')

module.exports = {
  name: 'vendor',
  mode: 'development',
  entry: [
    'axios',
    'babel-polyfill',
    'material-ui',
    'classnames',
    'mixpanel-browser',
    'ramda',
    'react',
    'react-dropzone-component',
    'react-dom',
    'react-ga',
    'react-helmet',
    'react-redux',
    'react-router-dom',
    'react-router-redux',
    'redux',
    'redux-thunk',
    'redux-saga'
  ],
  output: {
    path: path.resolve(__dirname, '../client'),
    filename: 'vendor.js',
    library: 'vendor_[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      name: 'vendor_[hash]',
      path: path.resolve(__dirname, '../client/manifest.json')
    }),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      }
    }),
    new webpack.ExtendedAPIPlugin(),
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
}

客户端.webpack.js

require('env2')('env.json')
const path = require('path')
const webpack = require('webpack')
const StatsPlugin = require('stats-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const merge = require('webpack-merge')
const baseConfig = require('./base.js')

module.exports = merge(baseConfig.moduleRules, {
  name: 'client',
  mode: 'development',
  target: 'web',
  // Good compromise between speed and quality, suitable for local development.
  devtool: 'cheap-module-eval-source-map',
  entry: [path.resolve(__dirname, '../app/index.js')],
  output: {
    filename: 'client.[chunkhash].js',
    chunkFilename: 'client.[chunkhash].js',
    path: path.resolve(__dirname, '../client'),
    publicPath: '/'
  },
  watchOptions: {
    poll: true
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'style.css'
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, '../client/manifest.json')
    }),
    new StatsPlugin('stats.json'),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('development')
      }
    })
  ],
  optimization: {
    runtimeChunk: 'single'
  }
})

server.webpack.js

const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const merge = require('webpack-merge')
const baseConfig = require('./base.js')

const res = p => path.resolve(__dirname, p)

const modeModules = res('../node_modules')
const entry = res('../lib/routes/resources/reactUrls.js')
const output = res('../buildServer')

// if you're specifying externals to leave unbundled, you need to tell Webpack
// to still bundle `react-universal-component`, `webpack-flush-chunks` and
// `require-universal-module` so that they know they are running
// within Webpack and can properly make connections to client modules:
const externals = fs
  .readdirSync(modeModules)
  .filter(x => !/\.bin|react-universal-component|webpack-flush-chunks/.test(x))
  .reduce((externals, mod) => {
    externals[mod] = `commonjs ${mod}`
    return externals
  }, {})

externals['react-dom/server'] = 'commonjs react-dom/server'

module.exports = merge(baseConfig.commons, {
  name: 'server',
  mode: 'development',
  target: 'node',
  // Good compromise between speed and quality, suitable for local development.
  devtool: 'cheap-module-eval-source-map',
  entry: [entry],
  externals,
  output: {
    path: output,
    filename: '[name].js',
    libraryTarget: 'commonjs2'
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '/style.css'
    }),
    new webpack.optimize.LimitChunkCountPlugin({
      maxChunks: 1
    }),
    new webpack.EnvironmentPlugin(['NODE_ENV'])
  ]
})

标签: webpack

解决方案


WebpackManifestPlugin可以用来解决这个问题。


推荐阅读