webpack4 30 steps to create the ultimate optimization react development environments, such as about to

Previous record a bit webpack4 use some basic usage tips, really did not expect to gain such a strong reaction, still very grateful to you for indulgence, not read about the 14 points webpack4 knowledge of fair trade

This article will react and webpack4 binding, set in one of the advantages of webpack, starting from 0 to build a powerful development environment react

All Benpian codes online codes react-webpack4-Cook , called translated: webpack4 and react in Luandun can be configured to follow the code, there are many pit before the line of code have been resolved. If it helps you, it may give a star. The thumbs concern is not lost

Foreword

Do not write an article foreword always feel less formal, about how I was introduced to complete the summary of a total knowledge points. In fact, many people have a look will be, done on a scrap of features (of course including me), this time, you need to develop a detailed plan slightly, like on my knowledge this will be listed first point, column a great direction, developing mind mapping, then write code according to the mind map, a clear plan, will be more effective, therefore, I hope you can follow along with the code Benpian gradual walk again, whether it is real development, or an interview, has of pull . Well, do not pull, you can look under the directory. Start now

First, the basic configuration

1, init project

mkdir react-webpack4-cook
cd react-webpack4-cook
mkdir src
mkdir dist
npm init -y
复制代码

2, installation webpack

yarn add webpack webpack-cli webpack-dev-server -D //webpack4把webpack拆分了
touch webpack.config.js
// webpack.config.js初始化内容
module.exports = {
    mode: "development",
    entry: ["./src/index.js"],
    output: {
        // 输出目录
        path: path.join(__dirname, "dist"),
        // 文件名称
        filename: "bundle.js"
    },
    module:{},
    plugins:[],
    devServer:{}
}
复制代码

3, install react and write code

This part of the code space too much, is to write some simple bit of code react and react-router, you can go to see the github, just to elaborate the basic functions

cd src 
cnpm i react react-router-dom -S
// 建立如下的文件目录,并编写安装react和react-router并编写react代码如下
|-src
│      index.js 主文件
├───pages
│      Count.jsx -- 实现了一个计数器的功能,点击按钮,会让数字增加,按钮会实时显示在页面上
│      Home.jsx -- 一个简单的文字展示
└───router
       index.js -- 路由配置文件,两个页面分别对应两个路由 count和 home
复制代码

4, babel compiled ES6, JSX, etc.

// @babel/core-babel核心模块    @babel/preset-env-编译ES6等 @babel/preset-react-转换JSX
cnpm i babel-loader @babel/core @babel/preset-env  @babel/plugin-transform-runtime   @babel/preset-react -D
// @babel/plugin-transform-runtime: 避免 polyfill 污染全局变量,减小打包体积
// @babel/polyfill: ES6 内置方法和函数转化垫片
cnpm i @babel/polyfill @babel/runtime
 {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "babel-loader"
          }
        ]
      }
 
复制代码

New .babelrc file

{
  "presets": ["@babel/preset-env","@babel/preset-react"],
  "plugins": ["@babel/plugin-transform-runtime"]
}
 
复制代码

5, the introduction of demand polyfill

Global index.js introduced under the src @babel/polyfilland write ES6 syntax, but this has a drawback:

  1. Global introduced @babel/polyfillin this way may be introduced into an unnecessary tag polyfill, so that a larger volume packaging

Change .babelrc, we only use translation to

npm install core-js@2 @babel/runtime-corejs2 -S
 
{
  "presets": ["@babel/preset-env",
              { "useBuiltIns": "usage" },
              "@babel/preset-react"],
  "plugins": ["@babel/plugin-transform-runtime"]
}
 
将将全局引入这段代码注释掉
// import '@babel/polyfill'
复制代码

This configured the introduction of demand. Configuring the introduction of the demand polyfill, the use es6the above function babelwill automatically import relevant polyfill, this can greatly reduce the volume of the packaged compiled

5, plug CleanWebpackPlugin

You will find that after several pack after each package will generate a bunch of files in the dist directory below, but the last time the file is still packaged, remove the old version of the file under the dist directory every time when we need to pack

cnpm install  clean-webpack-plugin -D
// 注意这个引入的坑,最新版的需要这样引入,而不是直接const CleanWebpackPlugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
 
plugins: [
    new CleanWebpackPlugin() 
]
复制代码

6, the use of plug-in HtmlWebpackPlugin

After the step of the operation, index.htmlit was also cleared. Therefore, we will use HtmlWebpackPluginplug-ins to generate html, and each packaged js automatically inserted into your index.htmlinside, and it can be based on one of your htmltemplates to create the final index.html, which means you can specify a template oh

cnpm install html-webpack-plugin -D
// 创建template.html
cd src
touch template.html
 
// 内容如下
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>react-webpack4-cook</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
 
// webpack.config.js做出更改
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      filename: 'index.html', // 最终创建的文件名
      template: path.join(__dirname, 'src/template.html') // 指定模板路径
    })
  ]
复制代码

7, the use of source-map, optimization of devtool

webpack in devtool option to control whether to generate, and how to generate source map. In short, source map is to help us locate the error information on the location of the file. The correct configuration source map, can improve development efficiency, faster positioning to the wrong location.

In webpack.config.js option mode, add the following sentence at:

devtool:"cheap-module-eval-source-map",// 开发环境配置
devtool:"cheap-module-source-map",   // 线上生成配置
复制代码

8, using WebpackDevServer

webpack-dev-serverThat is, to build a small local static file server, real-time reload function, providing web services to generate the resources to pack

  devServer: {
    hot: true,
    contentBase: path.join(__dirname, "./dist"),
    host: "0.0.0.0", // 可以使用手机访问
    port: 8080,
    historyApiFallback: true, // 该选项的作用所有的404都连接到index.html
    proxy: {
      // 代理到后端的服务地址,会拦截所有以api开头的请求地址
      "/api": "http://localhost:3000"
    }
  }
复制代码

9, using HotModuleReplacement (module replacement heat the HMR)

After the establishment of a local server development environment, when the content, the page will refresh synchronization, we now enter toCOunt page

  1. Click the button to figures added to a non-zero number, such as added 6

  2. Then you can change the text in the code button, just change something, you will find page refreshes, digital return to 0

This is obviously not what we want, want, can not save the state of the page, that is, after changing the code, or save the page numbers for the state 6 , which is to achieve partial change, first of all we need to use: HotModuleReplacementPlugin plug

devServer: {
    hot: true
},
 
plugins: [
    new webpack.HotModuleReplacementPlugin()
],
复制代码

After the bin, continue to operate more on top, click the button, the number increases, and then change the content, or did not save the state found. . . what? How to do

Correct@! This is not over yet, read on, we also need to react-hot-loader This plugin

10, react-hot-loader record react pages retained state state

We then continue to the top of the operation, divide it in four steps

cnpm i react-hot-loader -D
 
// 在主文件里这样写
 
import React from "react";
import ReactDOM from "react-dom";
import { AppContainer } from "react-hot-loader";-------------------1、首先引入AppContainre
import { BrowserRouter } from "react-router-dom";
import Router from "./router";
 
/*初始化*/
renderWithHotReload(Router);-------------------2、初始化
 
/*热更新*/
if (module.hot) {-------------------3、热更新操作
  module.hot.accept("./router/index.js", () => {
    const Router = require("./router/index.js").default;
    renderWithHotReload(Router);
  });
}
 
 
function renderWithHotReload(Router) {-------------------4、定义渲染函数
  ReactDOM.render(
    <AppContainer>
      <BrowserRouter>
        <Router />
      </BrowserRouter>
    </AppContainer>,
    document.getElementById("app")
  );
}
 
复制代码

Well, now you try again

11, compiled css and scss

cnpm install css-loader style-loader sass-loader node-sass -D
 
{
  test: /\.scss$/,
    use: [
      "style-loader", // 创建style标签,并将css添加进去
      "css-loader", // 编译css
      "sass-loader" // 编译scss
    ]
}
复制代码

12, integrated postcss

Most concerned about this dim ah? Automatically increase prefix, postcss-cssnext allows you to use future css properties, and do some processing compatible

cnpm install  postcss-loader postcss-cssnext -D
 
{
    test: /\.scss$/,
        use: [
            "style-loader", // 创建style标签,并将css添加进去
            "css-loader", // 编译css
            "postcss-loader",
            "sass-loader" // 编译scss
        ]
}
// 在刚才的home.scss 加上 transform: scale(2);
通过控制台查看,已经自动加上了前缀
复制代码

13, with pictures

cnpm i file-loader url-loader -D
 
file-loader 解决css等文件中引入图片路径的问题
url-loader 当图片较小的时候会把图片BASE64编码,大于limit参数的时候还是使用file-loader 进行拷贝
{
    test: /\.(png|jpg|jpeg|gif|svg)/,
    use: {
      loader: 'url-loader',
      options: {
        outputPath: 'images/', // 图片输出的路径
        limit: 10 * 1024
      }
    }
}
复制代码

14, handle fonts

{
        test: /\.(eot|woff2?|ttf|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg file
              publicPath: 'fonts/',
              outputPath: 'fonts/'
            }
          }
        ]
      }
复制代码

Two, webpack optimization

1, alias file path optimization

  1. extension: After specifying the file name plus the extension may not require or import extension in time, will in turn try to add extensions to match
  2. alias: alias configuration can accelerate the speed of lookup module webpack
  resolve: {
    extension: ["", ".js", ".jsx"],
    alias: {
      "@": path.join(__dirname, "src"),
      pages: path.join(__dirname, "src/pages"),
      router: path.join(__dirname, "src/router")
    }
  },
复制代码

14, using the static resource path publicPath (CDN)

CDN by deploying resources around the world, allows users to access resources nearby, quicker access. To access CDN, static resources need to be uploaded to the web page of CDN services, while access to these resources, use the URL CDN services provided.

output:{
 publicPatch: '//【cdn】.com', //指定存放JS文件的CDN地址
}
复制代码

2, MiniCssExtractPlugin, extract css file

If you do not do the configuration, we cssare directly packaged into jsthe inside, we hope to create a separate cssfile. Because alone generate css, js and css can be downloaded in parallel, to improve page load efficiency

cnpm install mini-css-extract-plugin -D
 
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
 
 {
        test: /\.scss$/,
        use: [
          // "style-loader", // b不再需要style-loader要已经分离处理
          MiniCssExtractPlugin.loader,
          "css-loader", // 编译css
          "postcss-loader",
          "sass-loader" // 编译scss
        ]
      },
 
 plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
  ]
复制代码

3, dividing the code loaded on demand, extracting common code

Why should achieve on-demand loading?

We now see, after packaging, all the pages, just one bundle.js, when we first load screen, it will be very slow. Because he downloaded the other pages of jsthe , that is to say, before the execution is completed, the page is finished! all! air! White! of! . If each page individually packaged js own, you can reload the page to enter your js at the time, the first screen you can load much faster

  optimization: {
    splitChunks: {
      chunks: "all", // 所有的 chunks 代码公共的部分分离出来成为一个单独的文件
    },
  },
复制代码

5, file compression

webpack4 long in production mode, the compressed code will be automatically

mode:productioin
复制代码

6, exposure to global variables

It can be used directly in the global variable $

 new webpack.ProvidePlugin({
      $: 'jquery', // npm
      jQuery: 'jQuery' // 本地Js文件
    })
复制代码

8, designated environment, define the environment variable

plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        VUEP_BASE_URL: JSON.stringify('http://localhost:9000')
      }
    }),
]
复制代码

9、css Tree Shaking

npm i glob-all purify-css purifycss-webpack --save-dev
 
const PurifyCSS = require('purifycss-webpack')
const glob = require('glob-all')
plugins:[
    // 清除无用 css
    new PurifyCSS({
      paths: glob.sync([
        // 要做 CSS Tree Shaking 的路径文件
        path.resolve(__dirname, './src/*.html'), // 请注意,我们同样需要对 html 文件进行 tree shaking
        path.resolve(__dirname, './src/*.js')
      ])
    })
]
复制代码

10、js Tree Shaking

Clear the code useless js code, only supports the introduction of import mode does not support the introduction of commonjs way

As long as the mode is the production will take effect, tree shaking develpoment is not effective, because in order to facilitate your debugger webpack

  optimization: {
    usedExports:true,
  }
复制代码

11, DllPlugin plug-packaged third-party libraries

The introduction of the project a lot of third-party libraries, these libraries over a long period of time, basic is not updated when packaged packaged packaged separately to improve the speed, but DllPlugin DLL plug-ins, the principle is the base on which pages the module pulled out packaged into dll file, when present in the module needs to import a dll, this module is no longer packaged, but to get the dll.

Installation jquery, introduced at the inlet and files. New webpack.dll.config.js file

/*
* @desc 静态公共资源打包配置
*/


const path = require('path')
const webpack = require('webpack')

const src = path.resolve(process.cwd(), 'src'); // 源码目录
const evn = process.env.NODE_ENV == "production" ? "production" : "development";

module.exports = {
    mode: 'production',
    entry: {
        // 定义程序中打包公共文件的入口文件vendor.js
        jquery: ['jquery']
    },

    output: {
        path: path.resolve(__dirname, '..', 'dll'),
        filename: '[name].dll.js',
        library: '[name]_[hash]',
        libraryTarget: 'this'
    },

    plugins: [
        new webpack.DllPlugin({
            // 定义程序中打包公共文件的入口文件vendor.js
            context: process.cwd(),

            // manifest.json文件的输出位置
            path: path.resolve(__dirname, '..', 'dll/[name]-manifest.json'),

            // 定义打包的公共vendor文件对外暴露的函数名
            name: '[name]_[hash]'
        })
    ]
}
复制代码

Add in the package.json

        "build:dll": "webpack --config ./build/webpack.dll.config.js",
复制代码

run

npm run build:dll
复制代码

You'll find more than a dll folder, inside a dll.js file, so we put our jquery these have been packaged separately, then how to use it?

Need to install a dependency npm i add-asset-html-webpack-plugin, it will dll.js file after we injected into the package we generated index.html. Webpack.base.config.js make changes in the document.

 new AddAssetHtmlWebpackPlugin({
 filepath: path.resolve(__dirname, '../dll/jquery.dll.js') // 对应的 dll 文件路径
 }),
 new webpack.DllReferencePlugin({
 manifest: path.resolve(__dirname, '..', 'dll/jquery-manifest.json')
 })
复制代码

Well, you can have it new webpack.DllReferencePlugin this plugin commented, packaged under test, the release package to try, I test results, notes money 5689, after the comment, 5302ms, only worse 300ms? Note that I am here only jquery package as a demo, if you have a lot of pulled out of it? ? ? Would not it be horrible. If you look dopey, it is recommended to go online to look at my code it, see at a glance

12, concurrent execution of tasks using happypack

Webpack run on Node. Is a single-threaded model, that Webpack need one at a processing task, can not handle multiple tasks simultaneously. Happy Pack can make Webpack do this, it will break down tasks to multiple child processes to execute concurrently, the child has been dealt with and then send the results to the primary process.

cnpm i -D happypack
 
// webpack.config.js
 rules: [
     {
        // cnpm i babel-loader @babel/core @babel/preset-env -D
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: [
          {
            // 一个loader对应一个id
            loader: "happypack/loader?id=busongBabel"
          }
        ]
      }
      ]
 
//在plugins中增加
plugins:[
      new HappyPack({
      // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
      id:'busongBabel',
      // 如何处理.js文件,用法和Loader配置中一样
      loaders:['babel-loader?cacheDirectory'],
      threadPool: HappyPackThreadPool,
  })
]
 
复制代码

13, PWA optimization strategy

In short: The first time you visit a site, if successful, to do a cache, when the server being down, you can still access this page, this is the PWA. I believe that you already know, this is only required in a production environment, we need to do deal with the PWA, in case of emergency.

 cnpm i workbox-webpack-plugin -D

const WorkboxPlugin = require('workbox-webpack-plugin') // 引入 PWA 插件
const prodConfig = {
  plugins: [
    // 配置 PWA
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true
    })
  ]
}

在入口文件加上
// 判断该浏览器支不支持 serviceWorker
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(registration => {
        console.log('service-worker registed')
      })
      .catch(error => {
        console.log('service-worker registed error')
      })
  })
}
复制代码

After configuration, you can package to the next dist directory, start a static server, visit the home page in the dist directory, and then shut down the server, you will be surprised to find that: the site turned out to be also able to visit, ha ha, is not it amazing?

15, the combined extracts webpacka common configuration

 开发环境与生产环境以及webpack配置文件的分离,具体需要用到webpack-merge,用来 合并 webpack配置
复制代码

16, the final profile separation (knock kick)

Due to time and space limitations, basically to end here. Above, either not mentioned or referred to some minor details, the source code on github basically have all inclusive, and if there is a need to refer to github profile, followed with their own copy of it, will be more more with less

Would like the world has nothing webpack configuration engineer

Are here, you may want to point a praise , give a star, plus followers. All Benpian codes online codes react-webpack4-Cook , called translated: webpack4 and react in Luandun can be configured to follow the code, there are many pit before the line of code have been resolved. If it helps you, it may give a star. The thumbs concern is not lost

Reproduced in: https: //juejin.im/post/5cfe4b13f265da1bb13f26a8

Guess you like

Origin blog.csdn.net/weixin_33816821/article/details/91435461