Vários arquivos html usando webpack

87

Estou tentando fazer algo em um projeto que não tenho certeza se é possível, estou errado ou entendendo algo errado. Estamos usando o webpack e a ideia é servir mais de um arquivo html.

localhost: 8181 -> atende index.html
localhost: 8181 / example.html -> atende example.html

Estou tentando fazer isso definindo vários pontos de entrada, seguindo a documentação :

A estrutura da pasta é:

/
|- 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="https://stackoverflow.com/style/default.css">
</head>
<body>
    <div id="container"></div>
    <script src="/main.bundle.js"></script>
</body>
</html>

exemplo.html:

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

Alguém sabe o que estou fazendo de errado?

Obrigado.

miguelitomp
fonte
Você consegue encontrar a solução para isso? Também estou procurando o mesmo caso de uso.
monica

Respostas:

118

Veja um ponto de entrada como a raiz de uma árvore que faz referência a muitos outros ativos, como módulos javascript, imagens, modelos e assim por diante. Quando você define mais de um ponto de entrada, basicamente divide seus ativos nos chamados blocos para não ter todo o seu código e ativos em um único pacote.

O que eu acho que você deseja alcançar é ter mais de um "index.html" para diferentes aplicativos que também se referem a diferentes partes de seus ativos que você já definiu com seus pontos de entrada.

Copiar um arquivo index.html ou mesmo gerar um com referências a esses pontos de entrada não é tratado pelo mecanismo de ponto de entrada - é o contrário. Uma abordagem básica para lidar com páginas html é usar o, html-webpack-pluginque não só pode copiar arquivos html, mas também tem um mecanismo extenso para modelagem. Isso é especialmente útil se você quiser que seus bundles tenham um sufixo de hash de bundle que seja bonito para evitar problemas de cache do navegador ao atualizar seu aplicativo.

Como você definiu um padrão de nome, já [id].bundle_[chunkhash].jsnão pode fazer referência ao seu pacote javascript, main.bundle.jspois ele será chamado de algo semelhante main.bundle_73efb6da.js.

Dê uma olhada no plugin html-webpack . Especialmente relevante para o seu caso de uso:

Você provavelmente deve ter algo assim no final (aviso: não testado)

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

Esteja ciente de fazer referência ao nome do ponto de entrada na matriz de blocos, portanto, em seu exemplo deve ser exampleEntry. Provavelmente, também é uma boa ideia mover seus modelos para uma pasta específica em vez de colocá-los diretamente na pasta raiz src.

Espero que isto ajude.

Andreas Jägle
fonte
4
Boa explicação, mas ainda me incomoda que você tenha que chamar 'new HTMLWebPlugin' para cada página diferente que você cria em seu projeto.
klewis
Todo mundo não gosta de chamar o 'novo HTMLWebPlugin' de cada uma das páginas. Precisa de alternativa.
ChosenUser
3

Você também pode usar o Copy Webpack Plugin se não precisar de duas compilações diferentes, ou seja, assumindo que deseja apenas servir um HTML diferente com o mesmo main.bundle.js.

O plugin é realmente muito simples (testado apenas no webpack v4):

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

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

Em seguida, example.htmlvocê pode carregar a compilação index.html. Por exemplo:

<!DOCTYPE html>
<html
<head>
    ...
    <title>Example</title>
</head>
<body>
    <div id="container"> Show an example </div>
    <script src="main.bundle.js"></script>
</body>
</html>
F Lekschas
fonte
1
existe alguma outra maneira possível de usar CopyWebpackPlugin e adicionar o arquivo bundle.js ao arquivo html por meio do webpack em vez de fornecer diretamente a referência de script no próprio arquivo html?
Sritam Jagadev
3

Para usar vários arquivos HTML ao Webpackusar HtmlWebpackPlugin :

Modifique o webpack.config.jsincorporando diretamente o código abaixo.

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

Você pode adicionar quantas páginas HTML forem necessárias ao htmlPageNamesarray. Certifique-se de que cada HTML e arquivo JS correspondente tenham o mesmo nome (o código acima assume isso).

RICHARD ABRAHAM
fonte
0

Existe outra solução, assumindo Webpack ^ 4.44.1. Ou seja, importando o HTML em seu aplicativo JS / TS.

Amostra de 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'),
    },
};

App correspondente

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 copiará about.html para a pasta de saída correspondente .

Alex Nolasco
fonte
0
plugins: [
  ...templates.map(template => new HtmlWebpackPlugin(template))
]

Este código ajudaria se você tiver muitos modelos :)

Pavel Rodionov
fonte