首页 > 解决方案 > WebPack 创建 index.html 后 CSS 和 Bundle 的脚本路径有点偏离

问题描述

出于某种原因,webpack 正在尝试将client我的 CSS 和 bundle 的脚本标签附加到 href。问题在于它是错误的。而且我不知道如何告诉它修剪那部分。

在迁移到 webpack 之前,这是我使用 Gulp 构建它时在生产环境中的样子: 在此处输入图像描述

请注意上面的一切是如何从客户端文件夹中植根的。你甚至看不到客户端文件夹,因为我认为 expressJS 说从那一点开始,所以你只能看到客户端中的根目录,例如libscripts等。

这是我使用 Gulp 时 dist 目录的样子: 在此处输入图像描述

以下是我为静态资产提供服务的方式。我的ExpressJS服务器将静态评估的根文件夹设置为dist/client. 即使我使用 Gulp 时也是如此:

  .use(
    express.static('dist/client', {
      maxage: oneYear,
    })
  )

转发到现在:它现在正在使用我的新 webpack.config

这是来自 IDE 的dist的屏幕截图,因为它现在是使用 webpack 后的样子:

在此处输入图像描述

但是现在index.html是由 webpack 生成的:

<!doctype html><html lang="en"><head><title>My Title</title><meta charset="utf-8"><link href="https://ink.global.ssl.fastly.net/3.1.10/css/ink.min.css"><script src="https://ink.global.ssl.fastly.net/3.1.10/js/ink-all.min.js"></script><script src="https://ink.global.ssl.fastly.net/3.1.10/js/autoload.js"></script><link href="../client/lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="../client/scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>

webpack.config.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');

const isProduction = process.env.NODE_ENV === 'production';

const html = () => {
  return new HtmlWebPackPlugin({
    template: './src/client/index.html',
    filename: './client/index.html',
    hash: true,
  });
};

const copyAllOtherDistFiles = () => {
  return new CopyPlugin({
    patterns: [
      { from: 'src/client/assets', to: 'client/lib/assets' },
      { from: 'src/server.js', to: './' },
      { from: 'src/api.js', to: './' },
      { from: 'package.json', to: './' },
      { from: 'ext', to: 'client/lib' },
      { from: 'feed.xml', to: 'client' },
      {
        from: 'src/shared',
        to: './shared',
        globOptions: {
          ignore: ['**/*supressed.json'],
        },
      },
    ],
  });
};

module.exports = {
  entry: './src/client/index.js',
  output: {
    filename: 'client/scripts/app.[hash].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  target: 'web',
  devServer: {
    writeToDisk: true,
  },
  devtool: 'source-map',
  optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
          },
        ],
      },
      {
        test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ['url-loader'],
      },
    ],
  },
  plugins: isProduction
    ? [
        new CleanWebpackPlugin(),
        new MiniCssExtractPlugin({
          filename: isProduction
            ? 'client/lib/assets/css/main.[hash].css'
            : 'main.css',
        }),
        html(),
        copyAllOtherDistFiles(),
      ]
    : [new CleanWebpackPlugin(), html(), copyAllOtherDistFiles()],
};

请注意,我的捆绑包生成的src包含../client/和我的CSS脚本的href相同。

这样做的问题是我的应用程序是从dist 文件夹的根目录提供的。client您会认为../client/or ./client/orclient/会起作用,但事实并非如此。当我运行该站点时,我得到了这个,因为它找不到捆绑包:

在此处输入图像描述

正如您在下面看到的,它源于浏览器中的客户端文件夹上下文的所有内容:

在此处输入图像描述

(在迁移到 webpack 之后,这也很奇怪,如果我告诉 ExpressJS 已经从客户端文件夹开始,为什么我会看到客户端文件夹?当我使用 Gulp 使用相同的确切代码时,我没有看到客户端文件夹,因为我已经从浏览器的上下文中进入了它)

index.html 因此,当我在 dist 文件夹中手动更改生成的文件时,只是为了看看是否可以修复它,一切都解决得很好(注意我将其更改为 just lib/and scripts/):

</script><link href="lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>

问题是我不知道如何让 webpack 在..client/生成 index.html 时去掉 URL 的那一部分。 我已经尝试使用, or or来添加 publicPath 属性,但到目前为止没有运气。'/''./'''

换句话说,这不会加载:http://localhost:8080/client/scripts/app.b4b3659d9f8b3681c26d.bundle.js

但这确实:

http://localhost:8080/scripts/app.b4b3659d9f8b3681c26d.bundle.js

http://localhost:8080/lib/assets/css/main.b4b3659d9f8b3681c26d.css

标签: javascriptreactjswebpack

解决方案


我认为只要您将输出资产写入与服务器上设置的公用文件夹相同的文件夹,那么它就可以工作。假设client仍然是公众:

.use(
  express.static('dist/client', {
    maxage: oneYear,
  })
)

我建议在客户端的 webpack 配置中将整个输出设置为clientdir :publicPath

output: {
  filename: 'scripts/app.[hash].bundle.js',
  path: path.resolve(__dirname, 'dist/client'),
  publicPath: '/'
}

使用上面的设置,我们不必指定 html 模板位置的文件夹:

new HtmlWebPackPlugin({
  template: path.resolve(__dirname, 'src/client', 'index.html'),
  filename: 'index.html',
  hash: true,
});

推荐阅读