A concept,

Webpack is a __ static module packaging tool __ for modern JavaScript applications. When WebPack works with an application, it internally builds a dependency graph that maps to each module required for the project and generates one or more bundles.

Second, the start

Create the webpack-demo-main folder.

CD webpack-demo-main // go to the file directory NPM init -y // NPM initialization -y means yes. NPM install webpack webpack-cli --save-devCopy the code

Open the package.json file in the project directory and expand it as follows:

{
  "name": "webpack-demo-main"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": []."author": ""."license": "ISC"
}
Copy the code

In this file, we add the private: true parameter, which is to ensure private. Remove the main argument. Now we will create the following directory structure, files, and content:

webpack-demo-main
  |- package.json
+ |- index.html
+ |- /src
+   |- index.js
Copy the code

index.js

//index.js
function comp() {
  const el = document.createElement('div');

  el.innerHTML = '< I > Hello X1AXX1A
      '

  return el;
}

document.body.appendChild(comp());
Copy the code

index.html

<! DOCTYPEhtml>
<html>
  <head>
    <meta charset="utf-8" />
    <title>X1AXX1A</title>
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>
Copy the code

Manage resources

3.1 Configuring inlet and Output

Create the webpack.config.js file in the project root directory and enter the following code:

//webpack.config.js
const path = require('path');

module.exports = {
    mode: 'development'.// Development environment, production mode
    entry: './src/index.js'.// Import file
    output: {
        filename: '[name].[contenthash].js'.// Output file
        path: path.resolve(__dirname, 'dist'),// Output file storage address}};Copy the code

The Entry property sets the project’s entry file output to indicate how and where WebPack should output your “bundles, assets, and anything else you package or load with WebPack.” | – filename Settings of the output file name | – path output file storage directory.

inNode.js,__dirnameAlways points to theThe js file being executedThe absolute path to.

Let’s print it in the webpack.config.js file__dirnameLook, this is the absolute path to the current webpack.config.js.

The path.resolve method resolves a sequence of paths or path fragments to absolute paths. A given sequence of paths is processed from right to left, with each subsequent path appended to the front until an absolute path is constructed.

path.resolve('/ directory 1/ directory 2'.'3'/directory);
// Return: '/ directory 1/ directory 2/ directory 3'

path.resolve('/ directory 1/ directory 2'.'/ directory 3/ directory 4/');
// Return: '/ directory 3/ directory 4'
Copy the code

The path.join method concatenates all the given path fragments together (using platform-specific delimiters as delimiters) and normalizes the generated path. If the connected path string is a zero-length string, a ‘.’ is returned, indicating the current working directory.

path.join(Directory '/ 1'.Directory '2'.'Directory 3/ Directory 4'.Directory '5'.'.. ');
// Return: '/ directory 1/ directory 2/ directory 3/ directory 4'
Copy the code

We’ll create a new dist directory, move index.html to dist, and change the script import path

//index.html
//<script src="./src/index.js"></script>
<script src="main.js"></script>
Copy the code

The script commands are defined in the scripts field of the package.json file.

/ /...
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"."build": "webpack" 
},
/ /...
Copy the code

Then perform

npm run build
Copy the code

There is an extra main.js file in the dist folder.

3.2 load CSS

To import a CSS file from a JavaScript module, you need to install style-loader and CSS-loader and add these loaders to the Module configuration.

npm install --save-dev style-loader css-loader
Copy the code

Then add the following code to webpack.config.js:

  const path = require('path');
 
 module.exports = {
   entry: './src/index.js'.output: {
     filename: '[name].[contenthash].js'.path: path.resolve(__dirname, 'dist'),},module: {
    rules: [{test: /\.css$/i,
        use: ['style-loader'.'css-loader'],},],},};Copy the code

The module loader can be called in chain mode. Each loader in the chain will transform the resource. The chain is executed in reverse order. The first loader passes its results (converted resources) to the next loader, and so on. Finally, Webpack expects the last loader in the chain to return JavaScript.

Therefore, ensure the sequence of loader: Style-loader is first, and CSS-loader is last. If this convention is not followed, WebPack may throw an error.

Css-loader will process the content imported by import require() @import URL and convert it into A JS object.

Let’s first remove style-loader and do a test. Try importing a CSS file from index.js and then printing it out. The style we printed out is converted into a JS array by CSS-Loader. As shown below: Modify index.js

import style from './index.css'

function comp() {
    const el = document.createElement('div');
  
    el.innerHTML = '< I > Hello X1AXX1A
      '
    console.log(style)
  
    return el;
  }
  
  document.body.appendChild(comp());
Copy the code

The index. CSS file is added in the same directory

div {
    color: red
}
Copy the code

Because style prints out an array, the page cannot be used directly. You can see that the font does not turn red.

Next we add the style-loader back. Rerun, the font is red. So style-loader basically adds the array generated by CSS-loader to js.

3.3 Loading Images

Webpack 5 can use built-in Asset Modules, which allow you to use resource files (fonts, ICONS, etc.) without having to configure an extra loader.

Before WebPack 5, commonly used:

  • raw-loaderImport the file as a string
  • url-loaderInline the file as a data URI into the bundle
  • file-loaderSend the file to the output directory

Asset Module Type, which replaces all of these Loaders by adding four new module types.

  • asset/resourceSend a separate file and export the URL. Previously by usingfile-loaderThe implementation.
  • asset/inlineExport the data URI of a resource. Previously by usingurl-loaderThe implementation.
  • asset/sourceExport the source code of the resource. Previously by usingraw-loaderThe implementation.
  • assetBetween exporting a data URI and sending a separate fileAutomatic selection. Previously by usingurl-loaderAnd configure the resource volume limitation implementation.

So all we need to do is add the following code.

{
    test: /\.(jpe? g|png|gif|svg)$/i,
    type: 'asset'.// Automatically choose between exporting a data URI and sending a separate file
}
Copy the code

See the official Asset Modules tutorial for details

3.4 Resolve (Resolve)

Common examples are alias, extensions resolve. Alias creates an alias for import or require to make module introduction easier. For example, some common modules in the SRC/folder create assets under SRC, store an image, and then import an image in index.js with this option.

import imgSrc from '@/assets/img.png'
Copy the code

Resolve. extentions attempts to resolve these file suffixes in order, that is, there is no need to write the file suffixes when importing the file. Webpack will resolve the file in the order of the configured file suffixes.

module.exports = {
  / /...
  resolve: {
        extensions: ['.vue'.'.js'].// Indicates that the file suffix can be omitted when importing files
        alias: {
            The '@': path.join(__dirname, 'src')
            // The alias configuration here must be consistent with the Paths alias in jsconfig
            // Import files in SRC component can be written @/component/...}},/ /...
}
Copy the code

However, when using alias, you may find that the intelligent hints for paths and functions are missing, and that it is easy to miswrite and inconvenient if path names are complex.

Add jsconfig.json to the root directory

{
    "compilerOptions": {
        "baseUrl": ". /".// Base directory for resolving non-relative module names
        "paths": {
            "@ / *": ["src/*"] // Specify the path map to calculate the alias relative to the baseUrl option
        },
      "experimentalDecorators": true Provide experimental support for the ES decorator proposal
    },
    "exclude": ["node_module"."dist"]}Copy the code

Note: If the configuration file is tsconfig.json when the project integrates TypeScript, set allowJs: true to jsconfig.json.

3.5 Converting ES6+ to ES5

In order to be compatible with most browsers, you need to parse the JS syntax into ES5 version. A third party loader called Babel helps Webpack handle ES6+ syntax.

3.5.1 track ofBabelWhat is it?

Babel is a JavaScript compiler

Babel is a toolchain for converting ECMAScript 2015+ version code into backwardly compatible JavaScript syntax so it can run in current and older versions of browsers or other environments.

Babel-loader allows you to translate JavaScript files using Babel and Webpack.

Install dependency packages

npm i -D babel-loader @babel/preset-env @babel/core
Copy the code

A major change with @ Babel 7, the original babel-XX package was moved to the Babel domain

  • @babel-coreThe core functions of Babel are contained in the @babel/core module
  • @babel/preset-envLoad the transformation plug-in for functionality not available in the target browser

webpack.config.js

/ /...
rules: [{test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader']}]/ /...
Copy the code

Create the. Babelrc file in the root directory

{
    "presets": [["@babel/preset-env"]]}Copy the code

Add some code to index.js

// Babel tests console.log([1,2,3].findindex (x => x === 4)) console.log(' ABC '.padstart (10))Copy the code



The arrow function was converted, indicating success.

@babel/preset-env provides a useBuiltIns parameter, and when set to Usage, only polyfills needed by the code will be included. Note that to set this parameter to usage, corejs must be set at the same time (warning will be given if not set, default is “corejs”: 2). Note: Here you still need to install @babel/polyfill(the current @babel/polyfill version installs “corejs”: 2 by default)

First of all, the reason for using core-js@3 is that no new features are added to the core-js@2 branch. New features are added to core-js@3. For example, if you’re using array.prototype.flat (), if you’re using core-js@2, it doesn’t include this new feature. In order to use more of the new features, we recommend that you use core-js@3.

npm install --save @babel/polyfill core-js@3
Copy the code
//.babelrc
{
    "presets": [["@babel/preset-env", {   
            "useBuiltIns": "usage"."corejs": 3}}]]Copy the code

3.5.2 @ Babel/plugin – transform – runtime

Babel uses very small helper code for some public methods, such as _extend / _classCallCheck. By default, it is added to every file that needs it. This can lead to repeated imports, which can be solved by @babel/ plugin-transform-Runtime.

The @babel/ plugin-transform-Runtime is usually only used in development, but the runtime relies on @babel/ Runtime, so @babel/ Runtime must be installed as a production dependency.

NPM i-d@babel /plugin-transform-runtime NPM i-d@babel /runtime //Copy the code

Add a line of configuration after the Presets

//.babelrc
{
    "presets": [["@babel/preset-env", {
            "useBuiltIns": "usage"."corejs": 3}]],"plugins": [
        "@babel/plugin-transform-runtime"]}Copy the code

To avoid global contamination, we used the @babel/runtime-corejs3 dependency and modified the configuration file

npm install @babel/runtime-corejs3 --save
Copy the code
//.babelrc
{
    "presets": [["@babel/preset-env"]],"plugins": [["@babel/plugin-transform-runtime", {
            "corejs": 3}}]]Copy the code

4. Manage output

In our test example above, the generated main.js had to be imported manually in index.html. However, as your application grows, and once you start using Contenthash in file names and exporting multiple bundles, it becomes difficult to continue manually managing index.html files.

This is where the HtmlWebpackPlugin comes in

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

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

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

HtmlWebpackPlugin will generate a new index.html file, replacing our original file.

Next we create a new public folder in the root directory, move index.html from dist to the public folder, and modify the webpack.config.js file

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  / /...
  plugins: [
    new HtmlWebpackPlugin({
      title: 'I am the title of the webpack.config configuration'.template: './public/index.html'.HTML / / compression
      minify: {
        removeComments: true.// Remove comments from HTML
        collapseWhitespace: true // Remove whitespace and newline characters}})].module: {
  / /...
Copy the code

This indicates that the index. HTML reference template under public is used. Dynamically introduce compiled related service resources. To configure the title attribute in the configuration file, we need to modify the title in the HTML file to get the configuration option. As follows:

<! --index.html-->
<! DOCTYPEhtml>
<html>
  <head>
    <meta charset="utf-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
  </body>
</html>
Copy the code

Since WebPack generates files and places them in the /dist folder, it does not keep track of which files are actually used in the project, resulting in many extra files in the DIST. In this case, it is necessary to use the clean-webpack-plugin to empty the Dist folder before creation

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

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    / /...
    plugins: [
    	new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'I am the title of the webpack.config configuration'.template: './public/index.html'.HTML / / compression
            minify: {
                removeComments: true.// Remove comments from HTML
                collapseWhitespace: true // Remove whitespace and newline characters}})].module: {
    / /...
Copy the code

5. Development environment

5.1 hot update

Running the NPM run build manually every time the code is compiled can be cumbersome. The Webpack-dev-server plug-in solves this problem.

Webpack-dev-server provides two main functions

  1. Provide web services for static files
  2. Auto Refresh and Hot replace (HMR)

Automatic refresh means that current changes to the Webpack are compiled automatically, and hot replacement means that various modules are updated at run time, that is, partial refresh

npm install --save-dev webpack-dev-server
Copy the code

webpack.config.js

module.exports = {
    / /...
    devServer: {
        contentBase: './dist'
    },
    / /...
}
Copy the code

The above configuration tells webpack-dev-server to serve the files in dist to localhost:8080. (Serve as server accessible file)

Webpack-dev-server is not written to any output files after compilation. Instead, you keep the bundle files in memory and then serve them to the server as if they were real files mounted on the server root path. If your page wants to find the bundle files in a different path, you can change this using the publicPath option in the Dev Server configuration.

Modify package.json to add running code

{
   / /...
   "scripts": {
    	"test": "echo \"Error: no test specified\" && exit 1"."dev": "webpack serve --open chrome"."build": "webpack"
    },
    / /...
}
Copy the code

Then execute it on the consolenpm run devYou can see that hot updates are implemented, but they look like F5 refreshes.We want to implement hot update, add a linehot: trueCan be

devServer: {
   contentBase: './dist'.hot: true
 },
Copy the code

5.2 Proxy Configuration

In the daily development process, often encounter cross-domain problems, here you can use devServer proxy configuration proxy, to achieve cross-domain requests.

webpack.config.js

module.exports = {
  / /...
  devServer: {
    proxy: {
      '/api': 'http://localhost:3000',}}};Copy the code

If now, right/API/users request will request broker to http://localhost:3000/api/users.

If you don’t want to pass/API, you need to rewrite the path:

module.exports = {
  / /...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000'.pathRewrite: { 
          '^/api': ' '},},},},};Copy the code

At that time, the will request broker/API/users request to http://localhost:3000/user

By default, backend servers running over HTTPS with invalid certificates will not be accepted. If necessary, you can modify the configuration as follows:

module.exports = {
  / /...
  devServer: {
    proxy: {
      '/api': {
        target: 'https://other-server.example.com'.secure: false,},},},};Copy the code

If you want to proxy multiple specific paths to the same target, you can use an array of one or more objects with the context attribute:

module.exports = {
  / /...
  devServer: {
    proxy: [{context: ['/auth'.'/api'].target: 'http://localhost:3000',},],},};Copy the code

By default, the agent retains the source of the host header, and changeOrigin can be set to True to override this behavior.

module.exports = {
  / /...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000'.changeOrigin: true,},},},};Copy the code

See the official documentation for more tutorials

5.3 DevTool

To make it easier to track errors and warnings, JavaScript provides source maps that map compiled code back to the original source code. Devtool controls whether and how the Source map is generated. Different DevTool Settings can cause performance differences. For details, try inline-source-map and modify the configuration file. webpack.confog.js

module.exports = {
    mode: 'development'.entry: './src/index.js'.// Import file
    output: {
        filename: '[name].[contenthash].js'.// Output file
        path: path.resolve(__dirname, 'dist'),// Output file storage address
    },
    devtool: "inline-source-map".// Add a line here
    / /...
Copy the code

Then we type console.llog in index.js (‘ This is an error ‘) and package the project.

As a result of packaging, a map file containing the corresponding base64 content is generated and inserted into main.bundle.js

Have a trysource-map



As you can see, there is a.map file at the end of main.bundle.js that specifies the specific reference to the map file

For example, there is a scenario where we need to debug an online project and can’t add a Source map to the code, but also need to debug. You can debug it by generating a.map file and adding it to the browser, as shown below.



This allows you to debug projects deployed online locally.

Avoid inline-*** and eval-*** in production as they increase the bundle size and reduce overall performance.

We can configure devtool in production with ‘source-map’, but do not deploy the map file on it. Alternatively, you can leave the devtool option unconfigured so that the map file is not generated.

5.4 External Extension (externals)

The externals configuration option provides the method to “exclude dependencies from the output bundle”. This means that dependencies imported in a project through import are not packaged into the bundle when packaged, but are accessed through script imports.

For example, importing jQuery from CDN instead of packaging it:

index.html

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
Copy the code

webpack.config.js

module.exports = {
  / /...
  externals: {
    jquery: 'jQuery',}};Copy the code

This strips out the dependencies that don’t need to be changed. Let’s add Jq to index.js and see what we print:

import $ from 'jquery';
console.log($('#app'));
Copy the code

5.5 the cache

SplitChunksPlugin can be used to separate modules into separate bundles. Webpack also provides an optimization function, can use optimization. RuntimeChunk option to the runtime code into a separate chunk. Set it to Single to create a Runtime bundle for all chunks

It is recommended to extract third-party libraries (such as Lodash or React) into a separate Vendor Chunk file because they are rarely modified as frequently as native source code.

We add the code in webpack.config.js

module.exports = {
    / /...
    // https://webpack.docschina.org/guides/caching/
    optimization: {
        moduleIds: 'deterministic'./ / using optimization runtimeChunk option to the runtime code into a separate chunk
        runtimeChunk: 'single'.splitChunks: {
            // Make use of the client's long-acting caching mechanism to hit the cache to eliminate requests and reduce the retrieval of resources from the server.
            // It also ensures that the client code and server code versions are consistent. This can be done by
            // Use SplitChunksPlugin's cacheGroups option.
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors'.chunks: 'all',},},},},}Copy the code

As you can see, the main file size is reduced from 1.78MiB to 13.2KiB

Adding optionsmoduleIds: 'deterministic'The hash of all three files has changed. This is because each module.id is incremented by default based on the resolve order. That is, when the parse order changes, the ID changes with it. So, in a nutshell:

The Main bundle changes as its new content changes. Vendor bundle changes as its module.id changes. The Manifest Runtime changes because it now contains a reference to a new module.

The first one and the last one both conform to the expected behavior, and the change of vendor hash is what we need to fix. We set optimization.moduleids to Deterministic.

Let’s rerun the project

Now, regardless of whether or not you add any new local dependencies,vendor hashThey should all be consistent.

Vi. Production environment

6.1 configuration

In a development environment, we need: a powerful source map and a Localhost Server with live reloading or hot Module replacement capabilities.

Production environment goals move to other areas, focusing on bundle compression, lighter source maps, resource optimizations, and so on to improve load times.

Following logical separation, we generally recommend writing separate WebPack configurations for each environment.

Create a new build folder in the root directory, create a new webpack.common.js file in the build folder to place the generic configuration, and create the production mode webpack.prod.js and development mode webpack.dev.js configuration files. To merge these configurations together, we will use a tool called Webpack-Merge.

The path to __dirname has changed

npm install --save-dev webpack-merge
Copy the code

webpack.common.js

//webpack.common.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/index.js'.// Import file
    output: {
        filename: '[name].[contenthash].js'.// Output file
        path: path.resolve(__dirname, '.. /dist'),// Output file storage address
    },
    resolve: {
        extensions: ['.vue'.'.js'].// Indicates that the file suffix can be omitted when importing files
        alias: {
            The '@': path.join(__dirname, '.. /src')
            // Import files in SRC can be written as @/component/...}},plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'I am the title of the webpack.config configuration'.template: './public/index.html'.HTML / / compression
            minify: {
                removeComments: true.// Remove comments from HTML
                collapseWhitespace: true // Remove whitespace and newline characters}})].module: {
        rules: [{test: /\.css$/i,
                use: ['style-loader'.'css-loader'],}, {test: /\.(jpe? g|png|gif|svg)$/i,
                type: 'asset'.// Automatically choose between exporting a data URI and sending a separate file
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: ['babel-loader']]}},// https://webpack.docschina.org/guides/caching/
    optimization: {
        // The deterministic option is beneficial for long-term caching
        moduleIds: 'deterministic'./ / using optimization runtimeChunk option to the runtime code into a separate chunk
        runtimeChunk: 'single'.splitChunks: {
            // Make use of the client's long-acting caching mechanism to hit the cache to eliminate requests and reduce the retrieval of resources from the server.
            // It also ensures that the client code and server code versions are consistent. This can be done by
            // Use SplitChunksPlugin's cacheGroups option.
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors'.chunks: 'all',},},},},};Copy the code

Webpack.dev.js development environment: debug location, hot replacement, etc

//webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
    mode: 'development'.devtool: 'inline-source-map'.devServer: {
        contentBase: '.. /dist'.hot: true}});Copy the code

Webpack.prod. js production environment: code compression, common module separation, resource optimization, etc

//webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
    mode: 'production'.devtool: "source-map"});Copy the code

We then redirect the script in package.json to the new configuration, Make the NPM run dev script webpack-dev-server use webpack.dev.js and the NPM run build script use webpack.prod.js

package.json

/ /...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"."dev": "webpack serve --open chrome --config build/webpack.dev.js"."build": "webpack --config build/webpack.prod.js"
  },
/ /...
Copy the code

6.2 Removing and Compressing the CSS

MiniCssExtractPlugin The MiniCssExtractPlugin extracts CSS into a separate file, creates a CSS file for each JS file containing CSS, and supports on-demand loading of CSS and SourceMaps.

npm install --save-dev mini-css-extract-plugin
Copy the code

The plugin extracts CSS into a separate style file and adds it to the HTML, so this conflicts with style-loader. Let’s modify the configuration file.

//webpack.common.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
/ /...
  plugins: [
    new MiniCssExtractniPlugin({
      filename: '[name].[contenthash].css'})].module: {
    rules: [{test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],},],},/ /...
};
Copy the code

The MiniCssExtractPlugin plugin is usually used in production environments, and we can continue to use style-loader in re-development environments.

So we will modify the configuration file again, using style-loader in webpack.dev.js and MiniCssExtractPlugin in webpack.prod.js

Next, compress the output CSS file and install the CSS-minimizer-webpack-plugin.

npm i -D css-minimizer-webpack-plugin
Copy the code
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
/ /...
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css'.chunkFilename: '[id].css',})],module: {
    rules: [{test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],},],},optimization: {
    minimizer: [
      new CssMinimizerPlugin({
          parallel: true // Use multi-process concurrent execution to improve build speed})],}};Copy the code

When we execute the package command, we can see that the CSS has been compressed.

This will only turn on CSS optimization in production.

If you also want to enable CSS optimization in your development environment, set optimization.minimize to true.

When not added, the resulting main file is 31.4kib

We add it to webpack.dev.js

//webpack.dev.js
module.exports = merge(common, {
    / /...
    optimization: {
        minimize: true}})Copy the code

Run it and you can see that the main file is 13.2KiB

6.3 js compressed

The TerserWebpackPlugin uses Terser to compress JavaScript.

If you are using WebPack V5 or above, you do not need to install this plugin. Webpack V5 comes with the latest Terser-webpack-plugin. If you use Webpack V4, you must install the version of Terser-webpack-Plugin V4.

For debugging convenience, the development process, do not compress the code. Let’s add it to the build environment.

// webpack.prod.js
const TerserPlugin = require("terser-webpack-plugin");
module.exports = merge(common, {
    // ...
    optimization: {
          // https://webpack.docschina.org/plugins/terser-webpack-plugin/
          Js / / compression
          minimize: true
          minimizer: [
              // https://webpack.docschina.org/plugins/terser-webpack-plugin/
              Js / / compression
              new TerserPlugin({
                  parallel: true // Use multi-process concurrent execution to improve build speed})]}})Copy the code

Run, package our project, and see the generated JS file compressed into a single line.

6.4 Image Compression

Oh ho, see other blog all have picture compression, I also add.

Go ahead and follow the website

Plug-ins need to be installed

npm install image-minimizer-webpack-plugin --save-dev
Copy the code

There are two modes of image optimization

One is lossless mode is lossy mode all the time

The website recommends lossless plug-ins

npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
Copy the code

The official website recommends lossy plug-ins

npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo --save-dev
Copy the code

Add code to webpack.prod.js

// webpack.prod.js
/ /...
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

module.exports = {
    / /...
    plugins: [
        / /...
        new ImageMinimizerPlugin({
            minimizerOptions: {
              // Non-destructive setting
              plugins: [['gifsicle', { interlaced: true }],
                ['jpegtran', { progressive: true }],
                ['optipng', { optimizationLevel: 5 }],
                [
                  'svgo',
                  {
                    plugins: [{removeViewBox: false,},],},],],},})]}Copy the code

Pack the project, and you can see that the images in DIST are smaller.

Note: this is based on file matching in “3.3 Loading images”. This is because such files need to be identified before they can be compressed. I missed matching jpeg files earlier. Compression errors occur. Thank me for asking the question without a coke.

7. Integrate Vue3

First, let Webpack recognize the.vue file. You need vue-loader plug-in, install plug-in.

npm install vue@next -S
npm install -D vue-loader@next @vue/compiler-sfc
Copy the code

Note: Vue2. X installs vue-template-complier

Vue-loader: parses and transforms the. Vue file, extracts the logical code script, style code style, and HTML template, and then sends them to the corresponding loader for processing.

Let’s start by configuring WebPack to recognize.vue files

//webpack.common.js
const { VueLoaderPlugin } = require('vue-loader/dist/index');

module.exports = {
	/ /...
    plugins: [
    	/ /...
    	new VueLoaderPlugin() // Plugin for parsing and converting.vue files].module: [
    	rules: [
            / /...
            {
                test: /\.vue$/,
                use: ['vue-loader'[}]]}Copy the code

Try creating the app. vue file in the SRC directory

<! --App.vue-->
<template>
    <div>Hello, X1AXX1A</div>
</template>
<script>
import { defineComponent } from "vue"
export default defineComponent({
  setup() {
      console.log('I'm a printer in the App')}})</script>
<style scoped>
@import '@/index.css';
</style>
Copy the code

Modify the index.js file

//index.js
import App from './App.vue'
import { createApp } from 'vue'

createApp(App).mount('#app')
Copy the code

Add div with id app to index.html

<! --index.html-->
<! DOCTYPEhtml>
<html>
  <head>
    <meta charset="utf-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
Copy the code

Next, load the Vue bucket Vuex, VUE-Router, and Axios

npm install vuex@next --save
Copy the code

Then create a store folder under the SRC directory and create index.js and modules folders under the Store folder.

The modules folder stores various store modules. We’ll add a new user module, user.js under modules

// src/store/modules
const state = () = > ({
  token: null
})

const getters = {
  token: (state) = > state.token
}

const mutations = {
  SET_TOKEN (state, payload) {
    state.token = payload
  }
}

export default {
  namespaced: true,
  state,
  getters,
  mutations
}
Copy the code

Then use require.context to dynamically load files in the Modules folder.

// src/store/index.js
import { createStore } from 'vuex'

const files = require.context('./modules'.false./\.ts$/)
const modules = {}

files.keys().forEach((key) = > {
    modules[key.replace(/(\.\/|\.ts)/g.' ')] = files(key).default
})
console.log('X1AXX1A modules', modules)
export default createStore({
    modules
})
Copy the code

Print and look at the obtained User module

This file is then imported in the entry file

// index.js
import App from './App.vue'
import { createApp } from 'vue'
import store from './store'

createApp(App).use(store).mount('#app')
Copy the code

At this point, you can use store in your component

We print in app.vue

// App.vue
import { defineComponent } from "vue"
import { useStore } from 'vuex'

export default defineComponent({
  setup() {
    let store = useStore()
    console.log('store', store)
    console.log('I'm the print of 123112 in the App')}})Copy the code

Next, install the router

npm install vue-router@next
Copy the code

Create a router folder under SRC and index.js under the router folder. Add the following code

// src/router/index.js

import { createRouter, createWebHashHistory } from 'vue-router'
import store from '.. /store'

const routes = [
  {
    path: '/ 404'.name: 'NotFound'.component: () = > import('@/views/NotFound.vue')}, {path: '/'.name: 'Index'.component: () = > import(/* webpackChunkName: "about" */ '@/views/Index.vue')}, {CatchAll (.*)' /:catchAll(.*)'
    // caught Error: Catch all routes ("*") must now be defined using a param with a custom regexp
    path: '/:catchAll(.*)'.// Special attention should be paid to placing it at the bottom
    redirect: '/ 404'}]const router = createRouter({
  history: createWebHashHistory(), Hash mode: createWebHashHistory, history mode: createWebHistory
  routes
})

export default router
Copy the code

Import the file in the import file

// index.js
import App from './App.vue'
import { createApp } from 'vue'
import store from './store'
import router from './router'

createApp(App).use(store).use(router).mount('#app')
Copy the code

Modify the App. Vue

// App.vue
<template>
  <router-view />
</template>
<script>
    import { defineComponent } from "vue"
    export default defineComponent({})
</script>
Copy the code

Create a new index. vue in views and add the following code to index. vue

// SRC /views/ index.vue <template> <div> </template> <script> import {defineComponent} from "vue" // import {  useStore } from 'vuex' import { useRouter, useRoute } from 'vue-router' export default defineComponent({ setup() { // let store = useStore() let router = useRouter() let route = useRoute() // console.log('store', store) console.log('router', router) console.log('route', }}) </script>Copy the code

Next up is Axios

npm i axios
Copy the code

Wrap AXIos, do request interception, and so on, as we like to do.

import axios from 'axios'
// Add request interceptor
axios.interceptors.request.use(function(config){
    // Do something before sending the request
    return config;
},function(error){
    // Do something when the request is wrong
    return Promise.reject(error);
});
  
// Add a response interceptor
axios.interceptors.response.use((response) = >{
    // Do something with the response data
    return response;
},(error) = >{
    return Promise.reject(error);
});
 
export default axios
Copy the code

With that in mind, we’re ready to start our Vue 3 project journey.

Finally, thank you for reading this article, I hope you can help, if you have any questions welcome to point out.

Reference:

Babel7