处理HtmlWebpackPlugin模板中链接标记内包含的.css文件

vshtjzan  于 9个月前  发布在  Webpack
关注(0)|答案(1)|浏览(150)

简要说明:我遇到了意外的输出/问题时,在使用MiniCssExtractPlugin和一些加载器提供给HtmlWebpackPlugin沿着的.html模板中的<link>标记内引用的.css文件。
目录结构:

| package.json
| webpack.prod.js
| src
  | css
    | main.css
    | another.css
    | ...
  | images
    | image1.png
      ...
  | scripts
    | script1.js
    | script2.js
  | templates
    | file1.html
    | file2.html
      ...
| ...

字符串
上面显示的目录结构的文件内容:script1.js包含对script2.js的引用,但没有对css文件的引用。.css文件仅使用./src/template s文件夹中包含的.html文件中的<link>标记引用。
webpack.prod.js内容:

const path = require('path');
const fs = require('fs');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

const htmlTemplates = fs.readdirSync(path.resolve(__dirname, 'src/templates')).filter(file => /\.html$/i.test(file));

module.exports = {
    mode: "production",
    entry: {
        index: "./src/scripts/script1.js",
    },
    output: {
        filename: 'static/[name]-[contenthash].bundle.js',
        path: path.resolve(__dirname, 'build'),
        publicPath: '/',
        assetModuleFilename: "static/[name]-markedByAssetModuleFilename-[contenthash].bundle[ext]",
        clean: true,
    },
    optimization: {
        minimizer: [
            new CssMinimizerPlugin(),
            new TerserPlugin({
                extractComments: false, //omit the creation of a separate LICENSE file
                terserOptions: {
                    format: {
                      comments: false, //remove the comments from the bundled output
                    },
                }            
            }),
        ],
    },
    plugins: [
        ...htmlTemplates.map((file) => {
            return new HtmlWebpackPlugin({
                template: `./src/templates/${file}`,
                filename: `htmlFiles/${file.replace(/\.html$/, '.bundle.html')}`,
                inject: 'head',
                scriptLoading: 'module',
                minify: {
                    collapseWhitespace: true,
                    removeComments: true,
                    removeRedundantAttributes: true,
                    removeScriptTypeAttributes: true,
                    removeStyleLinkTypeAttributes: true,
                    useShortDoctype: true,
                    minifyJS: true,
                    minifyCSS: true
                    }
            });    
        }),
        new MiniCssExtractPlugin({
            filename: 'static/[name]-[contenthash].bundle.css',
        }),
    ],
    module: {
        rules: [
            {
                test: /\.js$/i,
                exclude: [/node_modules/],
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                    },
                },
            },
            {
                test: /\.html$/i,
                use: ["html-loader"]
            },
            {
                test: /\.(png|jpe?g|gif|svg)$/i,
                type: "asset/resource",
            },
            {
                test: /\.css$/i,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ],
            }
        ],
    },
};


package.json

"devDependencies": {
    "@babel/preset-env": "^7.23.6",
    "babel-loader": "^9.1.3",
    "css-loader": "^6.8.1",
    "css-minimizer-webpack-plugin": "^5.0.1",
    "html-loader": "^4.2.0",
    "html-webpack-plugin": "^5.6.0",
    "mini-css-extract-plugin": "^2.7.6",
    "terser-webpack-plugin": "^5.3.10",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
    ...
    ...
  }


我期望的输出:
当我运行webpack --config webpack.prod.js我应该得到./build/htmlFiles文件夹包含所有“处理”的html文件.这些html文件应该有脚本标签捆绑script1.js和应该有链接标签指向被处理的css文件.处理的css文件应该根据指定的文件名为MiniCssExtractPlugin而不是每output.assetModuleFilename命名. css文件不应该为空.
我得到的输出:
./build/htmlFiles文件夹中的.html文件有指向./build文件夹中输出的css文件和脚本的链接标签和脚本标签。到目前为止一切顺利。
我发现在./build/static文件夹中.css文件都是根据ouput.assetModuleFilename下指定的名称命名的。所有.css文件也是空的,看起来像这样:

// extracted by mini-css-extract-plugin
export {};


我发现,如果我修改module.rules,使其具有include属性,如下图所示,并指向一个不存在的文件,那么./build/static中的所有.css文件都有css内容,但不再说// extracted by mini-css-extract-plugin。它们仍然根据output.assetModuleFilename命名。如果include确实指向存在的实际文件,则./build/static中的文件将不包含css内容,并且将为空。.build/static将有内容然后.我不明白这是怎么回事.

{
  test: /\.css$/i,
  use: [
    MiniCssExtractPlugin.loader,    //2. Extract css into files
    'css-loader'                    //1. Turns css into commonjs
  ],
  include: path.resolve(__dirname, './src/css/nonExistentFile.css'),
}


如何获得预期的输出?我想使用html模板中的所有css,使用指向build目录中已处理的.css文件的<link>标记。我不想在共享的script1.js文件中使用css导入语句。每个.html模板文件使用<link>标记指向自己的.css文件。
我已经试着阅读文档的最后2天,但不能弄清楚webpack刚刚。这是我第一次使用webpack。

mo49yndu

mo49yndu1#

  • 我想使用我的HTML模板内使用链接标签的所有CSS
  • 我不想在共享的script1.js文件中包含css导入语句

可以使用html-bundler-webpack-plugin
这个插件允许在HTML标签中直接使用JS和CSS/SCSS源文件
模板中的所有源文件路径都将被解析,并在捆绑输出中自动替换为正确的URL。解析后的资源将通过Webpack插件/加载器进行处理,并放置到输出目录中。
例如,有HTML模板包含对SCSS,JS和图像的引用:

<html>
  <head>
    <!-- relative path to SCSS source file -->
    <link href="./styles.scss" rel="stylesheet" />
    <!-- relative path to JS source file -->
    <script src="./main.js" defer="defer"></script>
  </head>
  <body>
    <h1>Hello World!</h1>
    <!-- relative path to image source file -->
    <img src="./picture.png" />
  </body>
</html>

字符串
生成的HTML包含输出文件名:

<html>
  <head>
    <link href="css/styles.05e4dd86.css" rel="stylesheet" />
    <script src="js/main.f4b855d8.js" defer="defer"></script>
  </head>
  <body>
    <h1>Hello World!</h1>
    <img src="img/picture.58b43bd8.png" />
  </body>
</html>


简单的Webpack配置:

const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlBundlerPlugin({
      // define a relative or absolute path to entry templates
      entry: 'src/views/',
      // OR define many templates manually
      entry: {
        index: 'src/views/home.html', // => dist/index.html
        'news/sport': 'src/views/news/sport/index.html', // => dist/news/sport.html
      },
      js: {
        // output filename of compiled JavaScript, used if `inline` option is false (defaults)
        filename: 'js/[name].[contenthash:8].js',
        //inline: true, // inlines JS into HTML
      },
      css: {
        // output filename of extracted CSS, used if `inline` option is false (defaults)
        filename: 'css/[name].[contenthash:8].css',
        //inline: true, // inlines CSS into HTML
      },
    }),
  ],
  // loaders for styles, images, etc.
  module: {
    rules: [
      {
        test: /\.(css|sass|scss)$/,
        use: ['css-loader', 'sass-loader'],
      },
      {
        test: /\.(ico|png|jp?g|webp|svg)$/,
        type: 'asset/resource',
      },
    ],
  },
};

备注

使用HTML模板器插件,HTML模板入口点,而不是JS。您不再需要在Webpack入口中定义SCSS和JS文件。
HTML插件取代了html-webpack-plugin和mini-css-extract-plugin的功能。

相关问题