Webpack has become the most popular and active packaging tool with its powerful features. It is also a “soft skill” that senior programmers must master when interviewing. The author introduces the use of Webpack based on the experience in the project. This article is the introduction of webpack entry, output and the use of various loaders, plugins and development environment, technical leaders please CTRL + W.

All the demo code for this article is in Webpackage Demo

concept

Take a look at the definition of Webpack:

In essence, Webpack is a static Module bundler for modern JavaScript applications. When WebPack works with an application, it recursively builds a Dependency graph containing every module the application needs, and then packages all of those modules into one or more bundles.

First, WebPack is a packer of static modules, so called static modules, including scripts, style sheets, images, and so on. When webPack is packaged, it first iterates through all static resources, builds a dependency graph based on resource references, and then divides modules into one or more bundles. Again, the diagram on piao’s official website vividly describes the process:

When it comes to WebPack, we have to mention four core concepts of WebPack

  • Entry: Indicates which module WebPack should use as a starting point for building its internal dependency graph
  • Output: Where do I export the bundles it creates
  • Loader: Enables Webpack to handle non-javascript files
  • Plugins: Used to perform a wider range of tasks

Your first packer

Let’s first install WebPack globally:

NPM install webpack webpack-cli -gCopy the code

Webpack can be built directly from the command line without using configuration files as follows:

webpack <entry> [<entry>] -o <output>
Copy the code

Here entry and output correspond to the above concept of entry and input, let’s create a new entry file:

//demo1/index.js
var a = 1
console.log(a)
document.write('hello webpack')
Copy the code

With the import file we also need to define the input path dist/bundle.js from the command line:

webpack index.js -o dist/bundle.js
Copy the code

Webpack then generates the packaged files in the dist directory.

We can also create a new HTML file in the project directory and import the bundled bundle.js file to see the effect.

The configuration file

Command line packaging is limited to simple projects. If our project is complex and has multiple entries, we can’t write down the entries every time we pack. Therefore, in general projects, configuration files are used for packaging; The commands for the configuration file are as follows:

webpack [--config webpack.config.js]
Copy the code

The default configuration file name is webpack.config.js. There are often multiple configuration files in a project. We can configure different files for different environments by using –config:

// Production environment configuration
webpack --config webpack.prod.config.js
// Development environment configuration
webpack --config webpack.dev.config.js
Copy the code

Multiple configuration types

The config file exports a configuration object through module.exports:

//webpack.config.js
var path = require('path');
module.exports = {
  mode: 'development'.// Import file
  entry: './index.js'.// Output directory
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'}};Copy the code

In addition to exporting an object, you can also export it as a function. The function carries parameters such as environment variables passed in from the command line. In this way, environment variables can be easily configured. For example, we can distinguish the formal and online development environments on the packaging line using env:

var path = require('path');
//env: environment object
module.exports = function(env, argv){
  return {
    // Other configurations
    entry: './index.js'.output: {}}};Copy the code

Alternatively, you can export as a Promise for asynchronously loading configurations, such as dynamically loading entry files:

module.exports = (a)= > {
    return new Promise((resolve, reject) = >{
        setTimeout((a)= >{
            resolve({
                entry: './index.js'.output: {}})},5000)})}Copy the code

The entrance

As mentioned above, the entry is the starting point for the entire dependency; Our common single-entry configuration is a page entry:

module.exports = {
    entry: './index.js',}Copy the code

It is short for:

module.exports = {
    entry: {
        main: './index.js'}},Copy the code

However, we may have more than one module in a page, so we need to inject multiple dependent files together. In this case, we need to use arrays.

module.exports = {
    entry: [
        // Multicast map module
        './src/banner.js'./ / the main module
        './src/index.js'.// Bottom module
        './src/foot.js'],}Copy the code

Sometimes a project may have more than one page, and multiple pages need to be packaged separately. Entry supports the form of incoming objects, and the code is in Demo3:

//demo3
module.exports = {
    entry: {
        home: './src/home.js'.list: './src/list.js'.detail: ['./src/detail.js'.'./src/common.js',}}Copy the code

Webpack then builds three different dependencies.

The output

The Output option controls how WebPack enters the compiled file module; There can be multiple entries, but only one output can be configured:

module.exports = {
    entry: './src/index.js'.output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'./ / the CDN address
        publicPath: '/',}}Copy the code

Here we have configured a single entry, and the output is bundle.js; If there are Multiple entries, this will not work. Webpack will prompt Conflict: Multiple chunks emit assets to the same filename. Webpack provides placeholders to ensure that each output file has a unique name:

module.exports = {
    entry: {
        home: './src/home.js'.list: './src/list.js'.detail: ['./src/detail.js'.'./src/common.js'],},output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].bundle.js',}}Copy the code

The webPack package is then packaged into three different bundles according to the name of the entry file; There are also the following different placeholder strings:

A placeholder describe
[hash] Hash of the module identifier
[chunkhash] Hash of chunk content
[name] The name of the module
[id] Module identifier
[query] The module’s query, for example, filename? The following string

Module (Chunk) Bundle (Chunk) Module (Chunk) Bundle (Chunk) Module exports are common in our code, such as module.exports. Chunk usually appears with entry, and Bundle always appears with output.

  • Module: We write source code, whether commonJS or AMdJS, can be understood as a module
  • Chunk: When the module source files we wrote are sent to Webpack for packaging, Webpack will generate chunk files based on the file reference relationship. Webpack will perform some operations on these chunk files
  • Bundle: After processing the chunk files, webpack finally outputs the bundle file. This bundle file contains the final source file that has been loaded and compiled, so it can be run directly in the browser.

Let’s take a closer look at these three concepts in the following diagram:

Conclusion:

Module, chunk, and bundle are the same logical code with three names in different transformation scenarios: module is written directly, chunk is processed by Webpack, and bundle can be run directly by the browser.

Hash, chunkhash, contenthash

Now that you understand the concept of chunk, it is easy to understand the difference between chunkhash and hash in the table above.

  • Hash: Is related to the construction of the entire project. Whenever a file changes in the project, the hash value of the entire project will change and all files will share the same hash value.
  • Chunkhash: it is related to the construction of the import file. The corresponding chunk is constructed based on the import file and the hash for each chunk is generated. When the entry file changes, the hash value of the corresponding chunk changes.
  • Contenthash: Creates a unique hash based on the content of the file. That is, when the content of the file changes, the hash changes.

model

In Webpack2 and Webpack3, we need to manually add plug-ins for code compression, the definition of environment variables, but also need to pay attention to the judgment of the environment, very tedious; The mode configuration is provided directly in webpack4 and can be used out of the box. Webpack also warns if configuration is ignored.

module.exports = {
  mode: 'development'};/ / equivalent to
module.exports = {
   devtool:'eval'.plugins: [
      new webpack.NamedModulesPlugin(),
      new webpack.NamedChunksPlugin(),
      new webpack.DefinePlugin({ 
        "process.env.NODE_ENV": JSON.stringify("development")]}})Copy the code

The development mode tells WebPack that I am now in development mode, which means that the packaged content should be development-friendly, easy to debug and enable real-time browser updates.

module.exports = {
  mode: 'production'};/ / equivalent to
module.exports = {
   plugins: [
      new UglifyJsPlugin(/ *... * /),
      new webpack.DefinePlugin({ 
        "process.env.NODE_ENV": JSON.stringify("production")}),new webpack.optimize.ModuleConcatenationPlugin(),
      new webpack.NoEmitOnErrorsPlugin()
   ]
}
Copy the code

Production mode is not development-friendly, just focused on packaging performance and generating smaller bundles. Don’t panic if you see a lot of plugins here, we’ll explain what they do.

Why do we use json.stringify (“production”) when defining environment variables in DefinePlugin? Would it be easier to use “production” instead?

Let’s first look at what json.stringify (“production”) generates; The result of the run is “”production””, notice that it’s not your eyes that are smudge or that there’s a little black dot on the screen, it’s actually one more set of quotes than “production”.

We can simply think of the DefinePlugin as replacing all the process.env.node_env in the code with the contents of the string. Suppose we have code in our code that determines the environment as follows:

//webpack.config.js
module.exports = {
  plugins: [
    new webpack.DefinePlugin({ 
      "process.env.NODE_ENV": "production"]}}),//src/index.js
if (process.env.NODE_ENV === 'production') {
    console.log('production');
}
Copy the code

The resulting code compiles like this:

//dist/bundle.js
The production variable is not defined in the code
if (production === 'production') {
    console.log('production');
}
Copy the code

However, we may not have defined the production variable in our code, which will cause the code to report an error directly, so we need to wrap a layer with json.stringify:

//webpack.config.js
module.exports = {
  plugins: [
    new webpack.DefinePlugin({ 
      //"process.env.NODE_ENV": JSON.stringify("production")
      / / equivalent to
      "process.env.NODE_ENV": '"production"']}}),//dist/bundle.js
if ("production"= = ='production') {
    console.log('production');
}
Copy the code

The compiled code should be fine.

Automatic page generation

In the above code, we found that we generated the index.html manually and then imported the packaged bundle. However, this would be too tedious. Moreover, if the generated bundle introduced hash values, the generated file name would be different each time, so we need a plug-in that generates HTML automatically. First we need to install this plugin:

npm install --save-dev html-webpack-plugin
Copy the code

In Demo3, we generated three different bundle.js files. We want to import these three files in three different pages. Modify the config file as follows:

module.exports = {
    // omit other code
    plugins: [
        new HtmlWebpackPlugin({
            // The referenced template file
            template: './index.html'.// The generated HTML name
            filename: 'home.html'.chunks: ['home']}),new HtmlWebpackPlugin({
            template: './index.html'.filename: 'list.html'.chunks: ['list']}),new HtmlWebpackPlugin({
            template: './index.html'.filename: 'detail.html'.chunks: ['detail']})]}Copy the code

Using index.html as the template file, we generated three different pages, home, List, and detail, and introduced different bundles through chunks. If there are no chunks, each page will import all the generated bundles.

The htML-webpack-plugin also supports the following fields:

new HtmlWebpackPlugin({
    template: './index.html'.filename: 'all.html'.// Inject title into the page
    title: 'html webpack plugin title'.// All chunks links are introduced by default
    chunks: 'all'.// Inject the page location
    inject: true./ / enable the hash
    hash: true.favicon: ' '.// Insert meta tags
    meta: {
        'viewport': 'width = device - width, initial - scale = 1.0'
    },
    minify: {
        // Clear the script tag quotes
        removeAttributeQuotes: true.// Clear comments in HTML
        removeComments: true.// Clear Spaces and newlines in HTML
        // Compress the HTML into a single line
        collapseWhitespace: false.// Compress the HTML inline style into a single line
        minifyCSS: true.// Clear elements with empty content (use with caution)
        removeEmptyElements: false.// Clear the type attribute of the style and link tags
        removeStyleLinkTypeAttributes: false}}),Copy the code

After setting title above, you need to set the template string in the template file:

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

loader

Loader is used to convert the source code of the module module. By default, WebPack can only recognize commonJS code, but we will introduce files such as vue, TS, less in the code, webPack can not process it. Loader extends webPack’s ability to handle multiple file types and convert these files into JS and CSS that browsers can render.

Module. rules allows us to configure multiple loaders. We can clearly see which loaders are applied to the current file type, and the loader code is in Demo4.

{
    module: {
        rules: [{test: /\.js$/.use: {
                    loader: 'babel-loader'.options: {}}}, {test: /\.css$/.use: [{loader: 'style-loader' },
                    { loader: 'css-loader'}]},]}}Copy the code

We can see that the rules property value is an array, and each array object represents a different matching rule; The test attribute is a regular expression that matches different file suffixes. Use indicates what loader to call to process the file. When there are multiple Loaders, use requires an array.

Multiple Loaders support chain transfer, which enables pipeline processing of resources. The return value of the previous loader is passed to the next loader. Loader processing has a priority, from right to left, from bottom to top; In the above demo, the CSS processing follows this priority, CSS-loader first, and then to style-loader; Therefore, we should pay attention to the sequence when writing loader.

CSS – loader and style – loader

Css-loader and style-loader have similar functions from their names. However, their functions are very different, but they are often used in pairs. Installation method:

npm i -D css-loader style-loader
Copy the code

Css-loader is used to interpret @import and URL (); Style-loader is used to insert the style sheet generated by CSS-loader into the page with the

/* /src/head.css */
.head{
    display: flex;
    background: # 666;
}
/* /src/foot.css */
.foot{
    background: #ccc;
}
/* /src/index.css */
@import './head.css';
@import './foot.css';
.wrap {
    background: # 999;
}
Copy the code

Add index. CSS to the entry file, and you can see the packaging effect. Insert three style tags in the page, and the code is in demo4:

Sass – loader and less – loader

These two loaders are used to handle sass and less styles. Installation method:

npm i -D sass-loader less-loader node-sass
Copy the code

Configure in config, code in demo4:

{
    // Other configurations
    rules: {
        test: /\.scss$/.use: [{
            loader: 'style-loader'
        }, {
            loader: 'css-loader'}, {loader: 'sass-loader'
        }]
    },{
        test: /\.less$/.use: [{
            loader: 'style-loader'
        }, {
            loader: 'css-loader'}, {loader: 'less-loader'}}}]Copy the code

postcss-loader

After 202 years, you don’t want to manually add -moz, -ms, -webkit and other browser private prefixes. Postcss provides many extensions to styles; Install without saying anything:

npm i -D postcss-loader
Copy the code

As usual, configure in config:

rules: [{
    test: /\.scss$/.use: [{
        loader: 'style-loader'
    }, {
        loader: 'css-loader'
    }, {
        loader: 'postcss-loader'}, {loader: 'sass-loader'
    }]
},{
    test: /\.less$/.use: [{
        loader: 'style-loader'
    }, {
        loader: 'css-loader'
    }, {
        loader: 'postcss-loader'}, {loader: 'less-loader'}}]]Copy the code

As we excitedly packed to see the effect, found that the style is still the same, and what has not changed.

This is because postCSS has only two main functions: the first is to parse CSS into an abstract syntax tree AST that JS can manipulate, and the second is to call plug-ins to process the AST and get results. So postCSS is usually handled by plug-ins, not directly, so we need to install some plug-ins first:

npm i -D autoprefixer postcss-plugins-px2rem cssnano
Copy the code

Create a new.browserslistrc file in the project root directory.

> 0.25%
last 2 versions
Copy the code

We extract the postcss configuration separately to postcss.config.js in the project root directory:

module.exports = {
    plugins: [
        // Automatically add the prefix
        require('autoprefixer'),
        // The px is converted to REM and applied to the mobile terminal
        require('postcss-plugins-px2rem') ({remUnit: 75 }),
        // Optimize merging CSS
        require('cssnano')]}Copy the code

With the Autoprefixer plug-in, our packaged CSS is automatically prefixed.

babel-loader

Many of you have experienced the pain of writing your JS code that doesn’t run on IE10 or IE11, and then trying to introduce various polyfills. Babel makes it easy for us to move from higher versions of ES6 or even ES7 to ES5; We’ll start by installing the dependencies required by Babel:

npm i -D babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime
npm i -S @babel/runtime
Copy the code

Add loader to config to process js:

{
    // Omit other configurations
    rules: [{
        test: /\.js/.use: {
            loader: 'babel-loader'}}}]Copy the code

Similarly, we extract the Babel configuration to the root directory and create a new. Babelrc file:

{
    "presets": [
        "@babel/preset-env"]."plugins": [
        "@babel/plugin-transform-runtime"]}Copy the code

We can try to write some ES6 syntax in index.js and see the code translated to ES5, which is in Demo4. Since babel-loader is slow in translation, we can see the time consumption of each loader after adding the time plug-in later. Babel-loader is the most time-consuming. So we’re going to use Babel as little as possible to translate files, we’re going to improve config,

{
    // Omit other configurations
    rules: [{
        test: /\.js$/.use: {
            loader: 'babel-loader'
        },
        // exclude: /node_modules/,
        include: [path.resolve(__dirname, 'src')]}}]Copy the code

Use $on the re for exact matching, exclude files in node_modules, and include will only match files in SRC. Include is recommended because it has a narrower and more accurate scope than exclude.

File – loader and url – loader

Both file-loader and URl-loader are used to process files such as images, fonts and ICONS. The url-loader works in two cases: If the file size is smaller than limit, the url-loader converts the file to base-64 encoding to reduce HTTP requests. If the file size is larger than the limit parameter, file-loader is called to process the file. Therefore, we prefer to use url-loader and install it first. Before installing url-loader, we also need to install file-loader first:

npm i file-loader url-loader -D
Copy the code

Next, modify config:

{
    // Omit other configurations
    rules: [{
        test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/.use: {
            loader: 'url-loader'.options: {
                //10k
                limit: 10240.// Generate the resource name
                name: '[name].[hash:8].[ext]'.// The path to generate the resource
                outputPath: 'imgs/'
            },
            exclude: /node_modules/,}}}]Copy the code

We add a centered background image of less than 10K to the body in the CSS:

body{
    width: 100vw;
    height: 100vh;
    background: url(./bg.png) no-repeat;
    background-size: 400px 400px;
    background-position: center center;
}
Copy the code

When you look at the body style after packaging, you can see that the image has been replaced with a Base64 URL in Demo4.

html-withimg-loader

If we reference an image on the page, we will find that the packaged HTML still references the image in the SRC directory, which is obviously wrong, so we need a plug-in to process the HTML reference image:

npm i -D html-withimg-loader
Copy the code

The HTML is configured in config as usual:

{
    // Omit other configurations
    rules: [{
        test: /\.(htm|html)$/.use: {
            loader: 'html-withimg-loader'}}}]Copy the code

Goose, however, opened the page and found this:

This is because each image is treated as a module in url-loader. We also need to modify it in url-loader:

use: {
    loader: 'url-loader'.options: {
        //10k
        limit: 10240.esModule: false}}Copy the code

So our image reference on the page is also modified, and the code is in Demo4.

note

HTML – withimg – loader can lead to HTML – webpack – plugin plug-in into the title of the template string < % = htmlWebpackPlugin. Options. The title % > failure, intact the display on the page; Therefore, if we want to keep both functions, we need to delete htMl-withimg-loader in config and reference the image as follows:

<img src="<%=require('./src/bg1.png') %>" alt="" srcset="">
Copy the code

vue-loader

Finally, a special vue-loader is used to process VUE files.

npm i -D vue-loader vue-template-compiler
npm i -S vue
Copy the code

Let’s start by creating a vue file in Demo5:

//src/App.vue <template> <div id="app"> <div class="box" @click="tap">{{title}}</div> </div> </template> <script> export Default {name: 'app', data(){return {title: 'app instance '}}, methods: { tap(){ this.title = this.title.split('').reverse().join('') } } } </script> <style> #app{ font-size: 16px; background: #ccc; } </style>Copy the code

Then reference it in the webpack entry file:

//src/main.js
import Vue from 'vue'
import App from './App.vue'

new Vue({
    render: h= > h(App)
}).$mount('#app')
Copy the code

Vue loader is not the same as other loaders. In addition to binding it to a. Vue file, we also need to introduce a plug-in for it:

const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
    module: {
        rules: [
        // Omit other loaders
        {
            test: /\.vue$/.loader: 'vue-loader'}},plugins: [
        new VueLoaderPlugin(),
    ]
}
Copy the code

So we can have fun writing vUE in code.

Setting up the development environment

In the demo above, we generated the DIST file using the command line package, and then opened the HTML directly or viewed the page through static-server. However, packaging every time we write code seriously affects the efficiency of development. We want to see the page immediately after we write the code. Webpack-dev-server provides a simple Web server that can be reloaded in real time.

First install dependencies in our project:

npm i -D webpack webpack-dev-server
Copy the code

The use of webpack-dev-server is the same as wepack, except that it starts an additional Express server. We will create a new webpack.dev.config.js configuration file in the project and configure the development environment separately. The relevant code is in Demo6:

module.exports = {
    // Omit other configurations
    devServer: {
        // Start the server port
        port: 9000.// The default is localhost, which can only be accessed locally
        host: "0.0.0.0".// Automatically open the browser
        open: false.// Enable module hot replacement
        hot: true.// Enable gzip compression
        compress: true
    },
    plugins: [
        // Hot update plugin
        new webpack.HotModuleReplacementPlugin({
        })
    ]
}
Copy the code

Start the server with the command line webpack-dev-server. After starting the server, we find that the root directory does not generate any files because webpack is packaged in memory. The reason for not generating files is that accessing code in memory is faster than accessing code in files.

Public /index.html pages sometimes refer to static files in the local directory. If you open the page directly, you will find that the reference to these static files is invalid. You can modify the working directory of the server and specify multiple static directory:

contentBase: [
  path.join(__dirname, "public"),
  path.join(__dirname, "assets")]Copy the code

Hot Module Replacemen (HMR) is that after the code is modified and saved, Webpack repackages the code and sends the new Module to the browser. The browser replaces the old Module with the new Module, so that the page can be updated without refreshing the browser.

It can be seen that the browser and webpack-dev-server are connected through a Websock. During initialization, the client saves a packaged hash value. During each update, the server listens for file changes, generates the latest hash value and pushes it to the client through websocket again. The client compares the hash value twice and sends a request to the server to return the updated module file for replacement.

Let’s click on the number of lines next to the source code to see what the compiled source looks like:

It was originally a simple ADD function, but it was difficult to understand the meaning of the original code through the module encapsulation of Webpack. Therefore, we need to map the compiled code back to the source code. Different configurations of Devtool have different effects and speeds. After combining performance and quality, we usually use cheap-module-eval-source-map in development environment and source-Map in production environment.

module.exports = {
    devtool: 'cheap-module-eval-source-map'.// Other configurations
}
Copy the code

Comparison of other modes:

plugins

We also introduced DefinePlugin, HtmlWebpackPlugin and other plugins above. We found that these plugins can affect the construction process of Webpack to varying degrees. There are also some commonly used plugins below, and the relevant code of plugins is in Demo7.

clean-webpack-plugin

Clean-webpack-plugin is used to clean up the bundle generated by the previous project before packaging. It automatically cleans the folder according to output.path. This plugin is used very frequently in production environments, where many bundles are hash generated and new ones are generated each time if not cleaned up, resulting in huge folders. This plugin is very easy to install and use:

npm i -D clean-webpack-plugin
Copy the code

After installation, we can configure it in config:

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
    // Other configurations
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            template: './public/index.html'.filename: 'index.html',}})]Copy the code

mini-css-extract-plugin

Our previous styles were inserted into the page via style-loader, but the production environment requires a separate style file to be extracted. The Mini-CSs-extract-plugin can help me strip styles from JS:

npm i -D mini-css-extract-plugin
Copy the code

We use style-loader in development environment and mini-CSS-extract-plugin in production environment:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
    // Other configurations
    module: {
        rules: [{test: /\.less/.use: [{
                    loader: isDev ? 'style-loader' : MiniCssExtractPlugin.loader
                },{
                    loader: 'css-loader'}, {loader: 'less-loader'}}}]],plugins: [
        new MiniCssExtractPlugin({
            filename: "[name].[hash:8].css",}})]Copy the code

After importing loader, we also need to configure plugin. The extracted CSS also supports the placeholder string in output.filename.

optimize-css-assets-webpack-plugin

We can find that although the production mode is configured, the packaged JS is compressed, but the packaged CSS is not compressed. In production we need to compress CSS:

npm i optimize-css-assets-webpack-plugin -D
Copy the code

And then also introducing plugins:

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
    // Other configurations
    plugins: [
        new OptimizeCSSAssetsPlugin(),
    ]
}
Copy the code

copy-webpack-plugin

As in Demo6, we introduced static resources in public/index.html, but webpack didn’t help us copy to the dist directory when we packed, so copy-webpack-plugin did a good job of copying for me

npm i -D copy-webpack-plugin
Copy the code

Configure the source and destination paths we need to copy in config:

const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
    plugins: [
        new CopyWebpackPlugin({
            patterns: [{from: 'public/js/*.js'.to: path.resolve(__dirname, 'dist'.'js'),
                    flatten: true,}]}),]}Copy the code

ProvidePlugin

ProvidePlugin can quickly load modules we want to introduce without requiring. JQuery import:

import $ from 'jquery'
$('.box').html('box')
Copy the code

But we can configure ProvidePlugin in config to use $without import:

module.exports = {
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery'.jQuery: 'jquery']}}),Copy the code

However, it would be confusing to introduce too many modules in a project without require, so I recommend loading some common ones like jQuery, Vue, Lodash, etc.

The difference between loader and plugin

With so many loaders and plugins introduced, let’s review the differences between them:

Loader: Since WebPack can only recognize JS, Loader acts as a translator to help WebPack preprocess the translation of other types of resources. Plugins: Plugins extend the functionality of WebPack by broadcasting many events while WebPack is running. Plugins can listen for these events and then change the output through the API provided by WebPack.

conclusion

Finally, this article is the foundation of Webpack, there are a lot of production environment optimization has not been written; So you look forward to optimization.

Reference:

Come again a dozen Webpack interview questions Webpack HMR principle analysis

For more front-end information, please pay attention to the public number [front-end reading].

If you think it’s good, check out my Nuggets page. Please visit Xie xiaofei’s blog for more articles