ไฟล์ html หลายไฟล์โดยใช้ webpack


89

ฉันกำลังพยายามทำอะไรบางอย่างในโปรเจ็กต์ที่ฉันไม่แน่ใจว่าเป็นไปได้หรือไม่ฉันกำลังทำอะไรผิดหรือเข้าใจผิด เราใช้ webpack และมีแนวคิดที่จะให้บริการไฟล์ html มากกว่าหนึ่งไฟล์

localhost: 8181 -> ทำหน้าที่ index.html
localhost: 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="https://stackoverflow.com/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="https://stackoverflow.com/style/default.css">
</head>
<body>
    ...
    <script src="/example.bundle.js"></script>
</body>
</html>

มีใครรู้บ้างว่าฉันทำอะไรผิด?

ขอขอบคุณ.


คุณสามารถหาวิธีแก้ปัญหานี้ได้หรือไม่? ฉันยังมองหากรณีการใช้งานเดียวกัน
โมนิกา

คำตอบ:


124

ดูจุดเข้าเป็นรากของต้นไม้ที่อ้างอิงถึงทรัพย์สินอื่น ๆ เช่นโมดูลจาวาสคริปต์รูปภาพเทมเพลตและอื่น ๆ เมื่อคุณกำหนดจุดเข้ามากกว่าหนึ่งจุดโดยพื้นฐานแล้วคุณจะแบ่งเนื้อหาของคุณออกเป็นกลุ่มที่เรียกว่าเพื่อไม่ให้มีรหัสและเนื้อหาทั้งหมดในกลุ่มเดียว

สิ่งที่ฉันคิดว่าคุณต้องการบรรลุคือการมี "index.html" มากกว่าหนึ่งรายการสำหรับแอปต่างๆที่อ้างอิงถึงส่วนต่างๆของเนื้อหาซึ่งคุณได้กำหนดไว้แล้วด้วยจุดเข้าใช้งานของคุณ

การคัดลอกไฟล์ index.html หรือแม้กระทั่งการสร้างไฟล์ที่มีการอ้างอิงไปยังจุดเข้าใช้งานเหล่านี้ไม่ได้รับการจัดการโดยกลไกจุดเข้า - มันเป็นอีกทางหนึ่ง วิธีการพื้นฐานในการจัดการเพจ html คือการใช้html-webpack-pluginซึ่งไม่เพียง แต่สามารถคัดลอกไฟล์ html ได้เท่านั้น แต่ยังมีกลไกมากมายสำหรับเทมเพลต สิ่งนี้จะมีประโยชน์อย่างยิ่งหากคุณต้องการให้บันเดิลของคุณต่อท้ายด้วยแฮชของบันเดิลซึ่งค่อนข้างจะช่วยหลีกเลี่ยงปัญหาการแคชเบราว์เซอร์เมื่อคุณอัปเดตแอป

ในขณะที่คุณได้กำหนดรูปแบบชื่อตามที่[id].bundle_[chunkhash].jsคุณไม่สามารถอ้างอิงกำจาวาสคริปต์ของคุณเป็นอย่างที่มันจะถูกเรียกว่าสิ่งที่ต้องการmain.bundle.jsmain.bundle_73efb6da.js

มีลักษณะที่เป็นHTML-webpack ปลั๊กอิน เกี่ยวข้องโดยเฉพาะกับกรณีการใช้งานของคุณ:

คุณน่าจะมีอะไรแบบนั้นในท้ายที่สุด (คำเตือน: ไม่ได้ทดสอบ)

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

exampleEntryโปรดทราบการอ้างอิงชื่อของจุดเข้าใช้งานในชิ้นอาร์เรย์ดังนั้นในตัวอย่างของคุณนี้ควรจะเป็น อาจเป็นความคิดที่ดีที่จะย้ายแม่แบบของคุณไปไว้ในโฟลเดอร์เฉพาะแทนที่จะให้มันอยู่ในโฟลเดอร์ root src โดยตรง

หวังว่านี่จะช่วยได้


4
คำอธิบายที่ดี แต่ยังคงรบกวนฉันที่คุณต้องเรียก 'HTMLWebPlugin ใหม่' สำหรับทุก ๆ หน้าที่คุณสร้างในโครงการของคุณ
klewis

ทุกคนไม่ชอบที่จะเรียกแต่ละหน้าว่า 'HTMLWebPlugin ใหม่' ต้องการทางเลือกอื่น
ChosenUser

4

ในการใช้ไฟล์HTML หลายไฟล์ในการWebpackใช้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)
  
};

คุณสามารถเพิ่มหน้า HTML ได้มากเท่าที่ต้องการในhtmlPageNamesอาร์เรย์ ตรวจสอบให้แน่ใจว่าแต่ละไฟล์ HTML และ JS ที่เกี่ยวข้องมีชื่อเดียวกัน (โค้ดด้านบนอนุมานว่า)


นี่เป็นแนวทางที่ดี แม้ว่าจะใช้ไวยากรณ์ ES6 ดูที่นี่ .
robev

3

นอกจากนี้คุณยังสามารถใช้การคัดลอก Webpack ปลั๊กอินถ้าคุณไม่ต้องสองสร้างความแตกต่างเช่นสมมติว่าคุณเพียงต้องการที่จะให้บริการที่แตกต่างกับ HTML main.bundle.jsเดียวกัน

ปลั๊กอินนั้นง่ายมาก (ทดสอบใน 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>

1
มีวิธีอื่นใดบ้างที่เป็นไปได้ในการใช้ CopyWebpackPlugin และเพิ่มไฟล์ bundle.js ลงในไฟล์ html ผ่าน webpack แทนที่จะให้การอ้างอิงสคริปต์ในไฟล์ html โดยตรง
Sritam Jagadev

0

มีวิธีแก้ปัญหาอื่นสมมติว่า Webpack ^ 4.44.1 นั่นคือการนำเข้า HTML ในแอป JS / TS ของคุณ

ตัวอย่าง 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 ไปยังโฟลเดอร์ผลลัพธ์ที่เกี่ยวข้อง


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

รหัสนี้จะช่วยได้หากคุณมีเทมเพลตจำนวนมาก :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.