【问题标题】:Multiple html files using webpack使用 webpack 的多个 html 文件
【发布时间】:2016-09-30 18:41:51
【问题描述】:

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

localhost:8181 -> 服务于 index.html
localhost:8181/example.html -> 提供 example.html

我正在尝试通过设置多个入口点来做到这一点,遵循documentation:

文件夹结构为:

/
|- 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>

example.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


【解决方案1】:

将入口点视为引用许多其他资产(如 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 文件夹中也是一个好主意。

希望这会有所帮助。

【讨论】:

  • 很好的解释,但它仍然困扰着我,您必须为您在项目中创建的每个不同页面调用“新 HTMLWebPlugin”。
  • 每个人都不喜欢把每个页面都称为“新的 HTMLWebPlugin”。需要替代品。
  • @Tahzzot 然后写一个循环,配置文件就是Javascript!
【解决方案2】:

使用 HtmlWebpackPluginWebpack 中使用多个 HTML 文件:

修改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 文件具有相同的名称(上面的代码假定)。

【讨论】:

  • 我必须使用excludeChunks: ["main"] 来防止我的 index.html 的捆绑包也出现在我的其他 html 中。
  • 非常感谢。这对我有用,@kyw 建议的更改以及在输出中使用占位符,如下所示: output: { path: path.resolve(__dirname, 'dist'), filename: '[name].js', publicPath : '' },
【解决方案3】:

如果您不需要两个不同的构建,也可以使用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>

【讨论】:

  • 有没有其他方法可以使用 CopyWebpackPlugin 并通过 webpack 将 bundle.js 文件添加到 html 文件中,而不是直接在 html 文件本身中提供脚本引用?
  • @SritamJagadev 不,CopyWebpackPlugin 只是逐字复制文件。如果你想修改 HTML,你需要 WebpackHtmlPlugin,比如注入脚本标签。
【解决方案4】:

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);

【讨论】:

    【解决方案5】:

    还有另一种解决方案,假设 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>
    

    关于.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 文件夹中。

    【讨论】:

      【解决方案6】:
      plugins: [
        ...templates.map(template => new HtmlWebpackPlugin(template))
      ]
      

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

      【讨论】:

      • 你能写出整个代码吗?不是很清楚。
      • @RockyKev 我不记得上下文,但要点是有一个变量来存储有关您的模板的信息。然后,您可以通过 webpack 运行您的模板,并在需要时编译它们。 ` const templates = [ { template: './src/hbs/pages/index.hbs', 文件名: './index.html' }, { template: './src/hbs/pages/index.hbs',文件名:'./articles/index.html' } ]`(抱歉格式错误)
      猜你喜欢
      • 1970-01-01
      • 2018-06-27
      • 2020-08-07
      • 1970-01-01
      • 1970-01-01
      • 2019-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多