使用 webpack 的多个 html 文件

问题描述 投票:0回答:8

我正在尝试在一个项目中做一些事情,但我不确定是否可能,我的方式错误或误解了某些事情。我们正在使用 webpack,其想法是提供多个 html 文件。

localhost:8181 -> 提供index.html
本地主机:8181/example.html -> 提供 example.html

我尝试按照文档

设置多个入口点来做到这一点

文件夹结构为:

/
|- package.json
|- webpack.config.js
  /src
   |- index.html
   |- example.html
   | /js
      |- main.js
      |- example.js

Webpack.config.js:

...
entry: {
    main: './js/main.js',
    exampleEntry: './js/example.js'
},
output: {
    path: path.resolve(__dirname, 'build', 'target'),
    publicPath: '/',
    filename: '[name].bundle.js',
    chunkFilename: '[id].bundle_[chunkhash].js',
    sourceMapFilename: '[file].map'
},
...

index.html

<!DOCTYPE html>
<html
<head>
    ...
    <link type="text/css" href="/style/default.css">
</head>
<body>
    <div id="container"></div>
    <script src="/main.bundle.js"></script>
</body>
</html>

示例.html:

<!DOCTYPE html>
<html
<head>
    ...
    <link type="text/css" href="/style/default.css">
</head>
<body>
    ...
    <script src="/example.bundle.js"></script>
</body>
</html>

有人知道我做错了什么吗?

谢谢你。

webpack webpack-dev-server
8个回答
180
投票

将入口点视为树的根,该树引用许多其他资产,例如 javascript 模块、图像、模板等。当您定义多个入口点时,您基本上会将资产分割成所谓的块,以免将所有代码和资产放在一个捆绑包中。

我认为您想要实现的是为不同的应用程序提供多个“index.html”,这些应用程序也引用您已经使用入口点定义的资产的不同块。

复制一个index.html文件或者甚至生成一个引用这些入口点的文件不是由入口点机制处理的——反之亦然。处理 html 页面的基本方法是使用

html-webpack-plugin
,它不仅可以复制 html 文件,而且还具有广泛的模板机制。如果您想让您的捆绑包带有捆绑包哈希后缀,这非常有用,这可以很好地避免更新应用程序时出现浏览器缓存问题。

当您将名称模式定义为

[id].bundle_[chunkhash].js
时,您不能再将 javascript 包引用为
main.bundle.js
,因为它将被称为类似
main.bundle_73efb6da.js
的名称。

看看 html-webpack-plugin。特别适合您的用例:

你最终可能应该有类似的东西(警告:未经测试)

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: 'src/index.html',
    chunks: ['main']
  }),
  new HtmlWebpackPlugin({
    filename: 'example.html',
    template: 'src/example.html',
    chunks: ['exampleEntry']
  })
]

请注意引用块数组中入口点的名称,因此在您的示例中,这应该是

exampleEntry
。将模板移动到特定文件夹中而不是将它们直接放在根 src 文件夹中可能也是一个好主意。


47
投票

要使用Webpack中的
多个HTML
文件,使用HtmlWebpackPlugin

直接嵌入以下代码来修改

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');

let htmlPageNames = ['example1', 'example2', 'example3', 'example4'];
let multipleHtmlPlugins = htmlPageNames.map(name => {
  return new HtmlWebpackPlugin({
    template: `./src/${name}.html`, // relative path to the HTML files
    filename: `${name}.html`, // output HTML files
    chunks: [`${name}`] // respective JS files
  })
});

module.exports = {
  entry: {
    main: './js/main.js',
    example1: './js/example1.js',
    //... repeat until example 4
  },
  module: { 
       //.. your rules
  };
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      chunks: ['main']
    })
  ].concat(multipleHtmlPlugins)
  
};

您可以根据需要向

htmlPageNames
数组添加任意数量的 HTML 页面。确保每个 HTML 和相应的 JS 文件具有相同的名称(上面的代码是假设的)。


4
投票

如果您不需要两个不同的版本,也可以使用 Copy Webpack Plugin,即假设您只想使用相同的

main.bundle.js
提供不同的 HTML。

这个插件真的非常简单(仅在 webpack v4 中测试过):

const CopyWebpackPlugin = require('copy-webpack-plugin');

const config = {
  plugins: [
    new CopyWebpackPlugin([
      { from: './src/example.html', to: './example.html' }
    ])
  ]
}

然后在

example.html
中,您可以从
index.html
加载构建。例如:

<!DOCTYPE html>
<html
<head>
    ...
    <title>Example</title>
</head>
<body>
    <div id="container"> Show an example </div>
    <script src="main.bundle.js"></script>
</body>
</html>

3
投票

RICHARD ABRAHAM 的解决方案对我来说效果很好,我还添加了 fsreaddir 函数来检测 html 文件

let htmlPageNames = [];
const pages = fs.readdirSync('./src')
pages.forEach(page => {
    if (page.endsWith('.html')) {
        htmlPageNames.push(page.split('.html')[0])
    }
})
console.log(htmlPageNames);

2
投票

还有另一种解决方案,假设Webpack ^4.44.1。也就是说,在您的 JS/TS 应用程序中导入 HTML。

示例 webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');


module.exports = {
    entry: { app: './src/index.ts' },

    mode: 'development',
    devtool: 'inline-source-map',
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'Development',
            template: path.join(path.resolve(__dirname, 'src'), 'index.ejs')
        }),
    ],
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: 'ts-loader',
                include: [path.resolve(__dirname, 'src')],
                exclude: /node_modules/,
            },
            {
                test: /\.html$/i,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]'
                        }
                    }
                ],
                // this exclude is required
                exclude: path.join(path.resolve(__dirname, 'src'), 'index.html')
            }
        ],
    },
    resolve: {
        extensions: ['.ts', '.js'],
    },
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        compress: true,
        port: 3900
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
};

对应应用程序

import './about.html';
    
console.log('this is a test'); 

index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Question</title>
</head>
<body>
     <a href="./about.html">About</a>
</body>
</html>

about.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>About</title>
</head>
<body>
    <p>This is an about page</p>
</body>
</html>

Webpack 会将 about.html 复制到相应的 output 文件夹中。


2
投票

回到@andreas-jägle 的观点。使用 'html-webpack-plugin':html-webpack-plugin html-webpack-plugin。但是,请优化您的代码以避免文件的重复

  plugins: ['index', 'page1', 'page2'].map(
    (file) =>
      new HtmlWebpackPlugin({
        template: './src/' + file + '.html',
        inject: true,
        chunks: ['index', 'main'],
        filename: './' + file + '.html' //relative to root of the application
      })
  )


1
投票
plugins: [
  ...templates.map(template => new HtmlWebpackPlugin(template))
]

如果您有很多模板,此代码将会有所帮助:)


1
投票

2024 年可以使用 html-bundler-webpack-plugin 而不是

html-webpack-plugin
。该插件从 HTML 中使用的源文件中提取 JS、CSS 和资源。使用此插件,
entrypoint
是HTML文件,所有使用的源资源都会自动提取。

您可以直接在 HTML 中加载单个源脚本、样式和图像。 源文件的路径必须是 HTML 文件或 Webpack 别名的相对路径。

index.html

<!DOCTYPE html>
<html
<head>
    ...
    <!-- load source file of style -->
    <link rel="stylesheet" href="./style/default.scss">
</head>
<body>
    <h1>Home</h1>
    <!-- load source file of image -->
    <img src="./images/homepage.png">
    <!-- load source file of script -->
    <script src="./js/main.js"></script>
</body>
</html>

示例.html

<!DOCTYPE html>
<html
<head>
    ...
    <!-- load source file of style -->
    <link rel="stylesheet" href="./style/default.scss">
</head>
<body>
    <h1>Example</h1>
    <!-- load source file of script -->
    <script src="./js/example.js"></script>
</body>
</html>

安装插件:

npm install html-bundler-webpack-plugin --save-dev

根据以下最低配置更改您的 webpack.config.js:

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

module.exports = {
  output: {
    path: path.join(__dirname, 'dist/'),
    publicPath: '/',
  },

  entry: {
    // define HTML files here
    index: './src/index.html',  // => dist/index.html
    example: './src/example.html', // => dist/example.html
    // ...
  },

  plugins: [
    new HtmlBundlerPlugin({
      js: {
        // JS output filename extracted from source script loaded in HTML via `<script>` tag
        filename: 'js/[name].[contenthash:8].js',
      },
      css: {
        // CSS output filename extracted from source style loaded in HTML via `<link>` tag
        filename: 'css/[name].[contenthash:8].css',
      },
    }),
  ],

  module: {
    rules: [
      // styles
      {
        test: /\.(css|sass|scss)$/,
        use: ['css-loader', 'sass-loader'],
      },
      // images
      {
        test: /\.(png|jpe?g|svg|ico)/,
        type: 'asset/resource',
        generator: {
          filename: 'img/[name].[hash:8][ext]',
        },
    },
    ],
  },
};

生成的 HTML 包含输出哈希文件名。源样式、脚本和图像会自动处理并放置在输出目录中

dist/

生成的index.html:

<!DOCTYPE html>
<html>
<head>
    ...
    <link href="/assets/css/default.f57966f4.css" rel="stylesheet">
</head>
<body>
    <h1>Home</h1>
    <img src="/assets/img/homepage.d2f4b855.png">
    <script src="/assets/js/main.b855d8f4.js"></script>
</body>
</html>

注意

不再需要在 JavaScript 中导入样式。
不再需要定义 JS 文件作为入口点。
现在,它可以直观地在 HTML 中运行。

© www.soinside.com 2019 - 2024. All rights reserved.