Varios archivos html usando webpack

87

Estoy tratando de hacer algo en un proyecto que no estoy seguro de que sea posible, estoy equivocado o estoy entendiendo mal algo. Estamos usando webpack y la idea es servir más de un archivo html.

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

Estoy tratando de hacerlo estableciendo múltiples puntos de entrada, siguiendo la documentación :

La estructura de carpetas es:

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

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

¿Alguien sabe lo que estoy haciendo mal?

Gracias.

miguelitomp
fuente
¿Puede encontrar la solución para esto? También estoy buscando el mismo caso de uso.
Monica

Respuestas:

118

Vea un punto de entrada como la raíz de un árbol que hace referencia a muchos otros activos, como módulos de JavaScript, imágenes, plantillas, etc. Cuando define más de un punto de entrada, básicamente divide sus activos en los llamados fragmentos para no tener todo su código y activos en un solo paquete.

Lo que creo que desea lograr es tener más de un "index.html" para diferentes aplicaciones que también se refieran a diferentes partes de sus activos que ya definió con sus puntos de entrada.

Copiar un archivo index.html o incluso generar uno con referencias a estos puntos de entrada no se maneja mediante el mecanismo de punto de entrada, es al revés. Un enfoque básico para manejar páginas html es usar el html-webpack-pluginque no solo puede copiar archivos html sino que también tiene un extenso mecanismo para crear plantillas. Esto es especialmente útil si desea que sus paquetes tengan un sufijo con un hash de paquete que sea bonito para evitar problemas de almacenamiento en caché del navegador cuando actualice su aplicación.

Como ha definido un patrón de nombre, ya [id].bundle_[chunkhash].jsno puede hacer referencia a su paquete de javascript, main.bundle.jsya que se llamará algo así como main.bundle_73efb6da.js.

Eche un vistazo al html-webpack-plugin . Especialmente relevante para su caso de uso:

Probablemente deberías tener algo así al final (advertencia: no probado)

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

Tenga en cuenta que debe hacer referencia al nombre del punto de entrada en la matriz de fragmentos, por lo que en su ejemplo debería ser así exampleEntry. Probablemente también sea una buena idea mover sus plantillas a una carpeta específica en lugar de tenerlas directamente dentro de la carpeta raíz src.

Espero que esto ayude.

Andreas Jägle
fuente
4
Buena explicación, pero todavía me molesta que tengas que llamar 'nuevo HTMLWebPlugin' para cada página diferente que crees en tu proyecto.
klewis
A todo el mundo no le gusta llamar al 'HTMLWebPlugin nuevo' cada una de las páginas. Necesita alternativa.
ChosenUser
3

También puede usar Copy Webpack Plugin si no necesita dos compilaciones diferentes, es decir, asumiendo que solo desea servir un HTML diferente con el mismo main.bundle.js.

El complemento es realmente simple (solo probado en webpack v4):

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

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

Luego example.html, puede cargar la compilación desde index.html. P.ej:

<!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
fuente
1
¿Hay alguna otra forma posible de usar CopyWebpackPlugin y agregar el archivo bundle.js al archivo html a través del paquete web en lugar de proporcionar directamente la referencia del script en el archivo html?
Sritam Jagadev
3

Para utilizar varios archivos HTML en el Webpackuso de HtmlWebpackPlugin :

Modifique webpack.config.jsincrustando directamente el siguiente código.

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

Puede agregar tantas páginas HTML como sea necesario a la htmlPageNamesmatriz. Asegúrese de que cada HTML y el archivo JS correspondiente tengan el mismo nombre (el código anterior asume eso).

RICHARD ABRAHAM
fuente
0

Hay otra solución, asumiendo Webpack ^ 4.44.1. Es decir, importar el HTML en su aplicación JS / TS.

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

Aplicación correspondiente

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 en la carpeta de salida correspondiente .

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

Este código ayudaría si tiene muchas plantillas :)

Pavel Rodionov
fuente