“This is the 16th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

1. HtmlWebpackPlugin

The HtmlWebpackPlugin plugin can be used to help us generate HTML files. Earlier we mentioned the second major negative aspect of the project:

  • ourHTMLFiles are written in the root directory, and finallyIt is not in the folder where the output is packagedindex.htmlfile;
  • However, in project deployment, it is necessary to have the corresponding entry file index.html;
  • So we need to package index.html as well;

So for HTML packaging processing, we can use the HtmlWebpackPlugin plugin.

Let’s install it first:

npm install html-webpack-plugin -D
Copy the code

In fact, with the plugin, we can delete the index.html file from our project directory, because there is an EJS HTML template in the plugin, and the HTML file will be automatically generated from this template and packaged into the output folder.

Next, let’s modify the webPack configuration file:

.// Unlike loader, plug-ins must be imported manually
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// Import the html-webpack-plugin without any deconstruction because it exports a class
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  ...
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin()
  ]
}
Copy the code

We then run the NPM run build command to package the package as follows:

You will notice that an index.html file is automatically generated in the output directory. How is this automatically generated?

  • By default, it is generated from a template of EJS;

  • In the source code for htML-webpack-plugin, there is a default_index.ejs module:

If you open the index.html file, you’ll also see that the code has removed useless whitespace (which means the file size is a bit smaller, which is a minor optimization), but we can format the code for ease of reading. Then you’ll see that it has already helped us introduce the bundle.js file via the

The automatic generation of import files is now ok, but there is one area that I would like to improve: can bundle.js files from the output folder be placed in the JS folder? Of course, we can modify output.filename:

.module.exports = {
  ...
  output: {...filename: 'js/bundle.js' // Package to js directory}}Copy the code

Let’s take a look at the package:

The bundle.js file is already in the js folder.

In real development, however, we typically use our own HTML template to generate entry files, rather than the default template of the HtmlWebpackPlugin.

Because we might want to add something special to our template:

  • Like adding a<noscript>The elementIn the user’sJavaScriptWhen being turned off, give corresponding prompt;
  • For example, inThe development ofVueReactprojectYou need a root element that can mount subsequent components:<div id="app"></div>;

Then we need our own index.html template. We can take a look at the package results of the Vue CLI created project:

As you’ll see, there’s also an index.html file in the dist folder of the Vue CLI project’s packaged output. If you open it and format the code, you’ll see that there’s a little bit more packaged stuff in there (because of the subcontracted stuff, which we’ll talk about later). There is also something that is not present in the index.html file generated by our current project packaging. Why is this? The reason is that Vue CLI-created projects specify their own template (./public/index.html) instead of using the default template to generate HTML files when the HtmlWebpackPlugin is used for packaging. We can copy the contents of the Vue CLI project template (./public/index.html) :

<! DOCTYPEhtml>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <! -- built files will be auto injected -->
  </body>
</html>
Copy the code

Then go to our project directory and create a new “public” folder as well. In the “public” folder, create a new “index.html” file and paste the content you just copied into it. Now that we have our own HTML template in our project, how can we use this template for packaging? Let’s modify the webPack configuration:

.module.exports = {
  ...
  plugins: [...new HtmlWebpackPlugin({
      template: './public/index.html' // Specify the path of the template to use}})]Copy the code

After modification, let’s try packing:

/public/index.html file. If we open this template file (which is actually an EJS template), we can see that the content of BASE_URL is filled at line 7:

<link rel="icon" href="<%= BASE_URL %>favicon.ico">
Copy the code

There is an EJS module syntax for populating data (<%= variable %>) that needs to be defined before using BASE_URL, but it is not currently defined anywhere, which is why this error is reported. If you delete this line of code and then package it, the error will not be reported. But deleting it is definitely not a foolproof solution. If we just want to populate a BASE_URL value, we need another plugin to help. This plugin comes with WebPack (meaning we don’t need to install it separately) : DefinePlugin. This plugin helps you define the value of a variable at compile time, which will be used to replace the variable in your code.

Let’s configure the DefinePlugin:

.// Get the DefinePlugin built into Webpack by deconstructing it. You can also get it directly by requiring ('webpack').defineplugin
const { DefinePlugin } = require('webpack');

module.exports = {
  ...
  plugins: [...new DefinePlugin({
      BASE_URL: "'/'" // Note that if the value is a string, it needs to be enclosed in quotation marks (single quotation marks inside double quotation marks/double quotation marks inside single quotation marks) because DefinePlugin will look for the value of the string in the context as another variable}})]Copy the code

After the configuration is complete, package the package. The result is as follows:

The template was successfully compiled to read the value of BASE_URL, and you can see that the <%= BASE_URL %> in the original template was replaced with a./ when used to generate our final index.html.

In addition, the title in the entry file is also configurable, and you don’t need to use the DefinePlugin for title as you did with BASE_URL, because you’ll find that in the./public/index.html template, There is a line of code like this:

<title><%= htmlWebpackPlugin.options.title %></title>
Copy the code

That is, the content of the title is retrieved from the title of options in the htmlWebpackPlugin variable in context. The title property of the options object in HtmlWebpackPlugin is the value of the title property in the HtmlWebpackPlugin object when plugins are configured:

.const HtmlWebpackPlugin = require('html-webpack-plugin'); .module.exports = {
  ...
  plugins: [...new HtmlWebpackPlugin({
      template: './public/index.html'.title: 'I'm the headline.' / / in htmlWebpackPlugin. Options. Read the title, will read the data}),... ] }Copy the code

NPM run build package

As you can see, the contents of

are the values we set.

Of course, HtmlWebpackPlugin has a lot of other parameters to configure, we can check its documentation on GitHub: github.com/jantimon/ht… .