Webpack configuration

The paper

Configure the React + typescript WebPack configuration from 0.

Reference: Configuring Webpack (top), Configuring WebPack (bottom)

Note: In order to eliminate possible bugs from different versions, the version information used for this project has been added to the download of the third package below, which does not necessarily mean that this version is used

Features: Mainly to achieve core functions

Address of making:


Initialize the project

Basic Project structure

Generate the project dependency file package.json

yarn init -y
Copy the code

Add the gitignore

You can customize it by using vscode’s gitignore plugin, or by using the react scaffolding configuration directly

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
Copy the code

Project Infrastructure

Start by creating three main folders under the project root:

  • public: Static resources used to hold a project
  • scripts: Used to store the webPack configuration file
  • src: The code file used to store the project

In order to distinguish the development and production environments of Webpack, you need two sets of configuration files, which have much in common. For code elegance, you can use the third-party package webpack-merge to import the common configuration into two separate files, so you need to create three files in the scripts directory:

  • webpack.common.js: used to write common configurations
  • webpack.dev.js: used to write development environment configurations
  • webpack.prod.js: used to write production environment configurations

To distinguish the environment

In the common configuration, there may be an option to use a different configuration in the development and production environments. In this case, there are two options:

  • Write it in dev and prod configuration files, but not in common
  • Sets an environment variable that identifies different environments

To choose the second option for code elegance, download the required third-party packages:

Cross-env: configures Node environment variables

Yarn add [email protected]Copy the code

For example, on a Mac PC, export NODE_ENV=development is used. On a Windows PC, set NODE_ENV=development is used

Create a new env.js file in the scripts/config directory to manage the startup environment

In Node, the global variable process represents the current Node process. Process. env contains information about the system environment. NODE_ENV is a user-defined variable that is configured when the startup command is configured below, written here first

const isDevelopment = process.env.NODE_ENV === 'development'
const isProduction = process.env.NODE_ENV === 'production'

module.exports = {
  isDevelopment,
  isProduction,
}
Copy the code

Managing common Constants

Create a constant.js file in the scripts directory for unified management of common constants

Write the public project root path and startup port and IP first

// scripts/constant.js

const path = require('path')

const PROJECT_PATH = path.resolve(__dirname, '.. / ')   // Project root path

const SERVER_HOST = '127.0.0.1'
const SERVER_PORT = 3000

export {
  PROJECT_PATH,
  SERVER_HOST,
  SERVER_PORT,
}
Copy the code

Webpack configuration paths generally require absolute path writing, so projects often have the following configuration, which is not very readable

module.exports = {
  entry: {
    app: path.resolve(__dirname, '.. /.. /src/index.js')},... }Copy the code

Using configured constants, you can do the following

module.exports = {
  entry: {
     app: path.resolve(PROJECT_PATH, './src/index.tsx'),},... }Copy the code

Webpack configuration

Webpack basic configuration

Download the third-party packages required for basic WebPack configuration:

Webpack: Used to compile JavaScript modules

Webpack-cli: Used to run Webpack on the command line interface

Webpack-dev-serve: You can start an HTTP service locally and specify its port, hot update, and so on through simple configuration

Webpack-merge: Merges webpack common configuration

Html-webpack-plugin: Used to package HTML files

Yarn add [email protected] yarn add [email protected] yarn add [email protected] yarn add [email protected] yarn The add [email protected]Copy the code

Add an HTML template file and a Webpack entry file, and write some random content in the entry file for stage testing

<! -- public/index.html -->
<! DOCTYPEhtml>
<html lang="en">
<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">
  <meta name="viewport" content="webpack5">
  <title>Webpack Config</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
Copy the code
// src/index.js
const ele = document.querySelector('#root')
ele.innerHTML = 'Stage test'
Copy the code

Add the startup project configuration

// package.json
"scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server --config ./scripts/config/webpack.dev.js"."build": "cross-env NODE_ENV=production webpack --config ./scripts/config/webpack.prod.js"
},
Copy the code

Configure the common configuration first, and then introduce the development and production environment configuration files respectively. Most of the configuration can be directly used by default, without additional declaration.

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { PROJECT_PATH } = require('.. /constant')

module.exports = {
  entry: {
    app: path.resolve(PROJECT_PATH, './src/index.js')},plugins: [
  	new HtmlWebpackPlugin({
      template: path.resolve(PROJECT_PATH, './public/index.html'),}}),]Copy the code

Configure the development environment, introduce the common configuration and add the webpack-dev-server configuration

const { merge } = require('webpack-merge')
const path = require('path')
const webpack = require('webpack')

const common = require('./webpack.common')
const { PROJECT_PATH, SERVER_HOST, SERVER_PORT } = require('.. /constant')

module.exports = merge(common, {
  mode: 'development'.devtool: 'cheap-module-source-map'.output: {
    filename: 'js/[name].js'.path: path.resolve(PROJECT_PATH, './dist')},devServer: {
    host: SERVER_HOST,
    port: SERVER_PORT,
    stats: 'errors-only'.clientLogLevel: 'none'.compress: true.open: true.hot: true.noInfo: true,},plugins: [
    // If hot: true is enabled, it will automatically recognize whether the plugin is declared or not. If it is not, it will be automatically introduced
    new webpack.HotModuleReplacementPlugin()
  ]
})
Copy the code

Devtool: enable source-map mode. If code error occurs, map to the wrong place in the browser.

The configuration functions of devServer are as follows:

  • Host: indicates the service IP address

  • Port: indicates the service port

  • Stats: Errors-only indicates that the terminal only prints error logs and does not print warning and other information affecting reading

  • Compress: True indicates that gzip compression is enabled to speed up website opening

  • Open: Set to true to automatically open the default browser when the project is started for the first time

  • Hot: If this parameter is set to true, hot replacement is enabled

  • ClientLogLevel: Set this parameter to None to remove unnecessary console information

  • NoInfo: Set to true to remove the packaging information displayed when the project is started

Hot enables hot replace instead of hot update. Webpack supports hot update by default. Hot update: Refresh the browser page when a file has been modified. When changing CSS and partial JS changes, the whole page refresh debugging experience is poor. After hot replacement is enabled, the page data can be changed without page refresh and the debugging is fasterCopy the code

In order to implement hot replacement of JS, you need to configure the module.hot.accept logic at the beginning of the code executing the entry file (CSS does not need to be configured, because the CSS-loader to be configured later already implements this logic).

// src/index.js

if (module && module.hot) {
  module.hot.accept(); }...Copy the code

The project will then adapt to typescript and the above code will report an error: the type NodeModule does not have the property HOT, so to avoid coming back later to change the problem, the next third-party package will fix the problem

@types/webpack-env: API declaration file containing webpack

Yarn add @ types/[email protected]Copy the code

ClientLogLevel before and after this function is enabled: After this function is enabled, only THE HMR information is displayed in the browser. The two WDS information is removed to prevent the browser from printing too many useless information

After noInfo is enabled, a lot of packaging information is lost on the terminal


Although the packaging message is missing, the packaging progress disappears, which is not conducive to the development experience, so use third-party packages to display the packaging progress bar

Webpackbar: displays the packaging progress bar

Yarn add [email protected]Copy the code
// scripts/config/webpack.common.js
const WebpackBar = require('webpackbar')

module.exports = {
  plugins: [...new WebpackBar({
      name: 'Link Startou!!! '.color: '#52c41a']}}),Copy the code

The production environment usually has hash values for output files, while the development environment does not. When the development environment starts with webpack-dev-server, it does not actually produce files in the project, but in memory

// scripts/config/webpack.prod.js
const { merge } = require('webpack-merge')
const path = require('path')

const common = require('./webpack.common')
const { PROJECT_PATH } = require('.. /constant')

module.exports = merge(common, {
  mode: 'production'.devtool: false.output: {
    filename: 'js/[name].[contenthash:8].js'.path: path.resolve(PROJECT_PATH, './dist')}})Copy the code

The difference between hash values:

Hash: Every time you modify any file, the hash of all file names will change, so if you modify any file, the entire project’s file cache will be invalidated

ChunkHash: If the package is from the same chunk, the hash value is the same. ChunkHash does not apply to files on the same chunk. For example, if a JS file is imported into a CSS file, they belong to the same chunk. The resulting file cs and JS will become a new hash

Contenthash: Generates hash values based on the contents of the file. Different files must have different hash values (as long as the content of the file is not modified, it must be the same hash, and changes will be replaced by another one), so that the browser can only remove the cache of the changed file (only the changed file has been renamed).

Stage of testing

Test at the end of each phase to ensure that the previous version is stable when you add the configuration

Start YARN Start and Yarn Build. If WebPack works properly, the basic configuration is complete


To configure the CSS

The reason to configure CSS first rather than JS is that webpack already supports native JS and HTML packaging, so CSS should be configured first to experience the full functionality

CSS Import

Download the required third-party packages:

Style-loader: Inserts the CSS code from the JS file into the HTML template file so that the web page can display the style normally

Mini-css-extract-plugin: it is the same as style-loader, but after packaging, it will generate CSS files separately instead of directly writing in HTML files. It is used in production environment, and development environment does not need to generate additional files using style-loader

Css-loader: enables JS to import CSS code by using commands such as import or require

Yarn add [email protected] yarn add [email protected] yarn add [email protected]Copy the code
// scripts/config/webpack.common.js

// Since sass and less need to use the same rules later, so this rule is removed
const getCssLoaders = () = > [
  isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, 
  {
    loader: 'css-loader'.options: {
      modules: {
        localIdentName: "[local]--[hash:base64:5]"
      },
      sourceMap: isDevelopment,
    }
  }
]

module.exports = {
  ...
  module: {
    rules: [{test: /\.css$/,
        use: [...getCssLoaders()]
      }
    ]
  },
}
Copy the code

Options configuration of CSS-loader:

  • Open modules:css module, depending on personal habits, you can directly set false if you do not use it, otherwise the packaging speed will be affected.localIdentNameRepresents a custom class name, hashed to ensure that class names are globally uniform
  • SourceMap: based on truedevtoolError mapping CSS, production environment does not need mapping all values given here are for development environment

Add the mini-CSS-extract-plugin rule to the production environment

// scripts/config/webpack.prod.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')


module.exports = merge(common, {
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css'.chunkFilename: 'css/[name].[contenthash:8].chunk.css',})]})Copy the code

Compatible with the style

Some CSS styles have different prefixes in different browser kernels. In order to write a CSS package that automatically adds all prefixes, you need to configure webPack and download third-party packages:

Postcss-loader: different from SASS /less, postCSs-loader is not a preprocessor. It is a toolkit that can be used with plug-ins to convert CSS

Postcss-preset -env: Converts the latest CSS syntax to a syntax that can be understood by the browser of the target environment, regardless of browser compatibility. Autoprefixer prefixes used to be required, but now the new version has the built-in autoprefixer function

Yarn add [email protected] yarn add [email protected]Copy the code

Rewrite the scripts/config/webpack.com mon. Packaging of js CSS rule function

const getCssLoaders = () = > {
  const cssLoaders = [
    isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader, 
    {
      loader: 'css-loader'.options: {
        modules: {
          localIdentName: "[local]--[hash:base64:5]"
        },
        sourceMap: isDevelopment,
      }
    }
  ]
  
  // In development environments, chrom is not a problem, so it is only used in production environments
  isProduction && cssLoaders.push({
    loader: 'postcss-loader'.options: {
      postcssOptions: {
        plugins: [
          isProduction && [
            'postcss-preset-env',
            {
              autoprefixer: {
                grid: true}}]]}}})return cssLoaders
}
Copy the code

Note that the PostCSS-loader processes the CSS. The sass-Loader and less-Loader to be configured convert the preprocessor to THE CSS code. Therefore, they are executed before the PostCSS-Loader

Postcss-preset -env configuration:

  • Autoprefixer: Enable the autoprefix function. Some functions are disabled by default, such as grid style. Some browsers do not support it, so it is disabled by default

To function, you also need to configure the Browserslist property in the package.json file

{
    "browserslist": [
        "0.2%" >."not dead"."ie >= 9"."not op_mini all"],}Copy the code

>0.2% : compatible with more than 98% of major browsers

Not dead: disables disabled browsers

Internet Explorer >= 9: Only Internet Explorer 9 or later is compatible

Not op_mini all: not compatible with any Opera Mini browsers (the main reason is that it has been discontinued for a long time and is no longer used)

Note that there is a sinkhole: configuring the Browserslist field will cause webpack-dev-server’s hot update functionality to be disabled directly. To avoid this, add the target attribute to Webpack

// scripts/config/webpack.dev.js

module.exports = merge(common, {
	/ /... other
    target: 'web',})Copy the code
// scripts/config/webpack.prod.js

module.exports = merge(common, {
	/ /... other
    target: 'browserslist',})Copy the code

The preprocessor

Download the required third-party packages:

Less: provides dependencies for less-loader

Less-loader: Converts less code to CSS code

Node-sass: provides a dependency for sas-loader

Sass-loader: Converts SASS code to CSS code

Yarn add [email protected] yarn add [email protected] yarn add [email protected] yarn add [email protected]Copy the code

If the download fails, try CNPM or add “Node-sass “:”^5.0.0” to package.json to lock the version, and then yarn install

At scripts/config/webpack.com mon. Js configured in less and sass

module: {
    rules: [{test: /\.css$/,
        use: [...getCssLoaders()]
      },
      {
        test: /\.less$/,
        use: [
          ...getCssLoaders(),
          {
            loader: 'less-loader'.options: {
              sourceMap: isDevelopment,
            }
          }
        ]
      },
      {
        test: /\.scss$/,
        use: [
          ...getCssLoaders(),
          {
            loader: 'sass-loader'.options: {
              sourceMap: isDevelopment,
            }
          }
        ]
      },
    ]
  },
  ...
}
Copy the code

To optimize the

Compress CSS

Download the required third-party packages:

Css-minimizer-webpack-plugin: Compress packed CSS files in production environments

Yarn add [email protected]Copy the code
// scripts/config/webpack.prod.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = merge(common, {
  / /... other
  optimization: {
    minimize: true.minimizer: [new CssMinimizerPlugin()
    ]
  }
})
Copy the code

Optimization: The optimization property was added after Webpack4 to store optimally packaged configurations, while the Minimizer property stores an array of plug-ins that can be used for code compression. Minimize true to enable the Minimizer configuration

Stage of testing

Test whether the CSS can be packaged properly

// src/index.js
import style from './index.scss'

const ele = document.querySelector('#root')

const newEle = document.createElement("div")
newEle.className = style.ele
newEle.innerHTML = 'Test CSS Module'
ele.appendChild(newEle)
Copy the code
// src/index.scss
.ele {
  background-color: bisque;
  display: flex;
}
Copy the code

Checkpoint:

  • Check whether the SCSS style is normal
  • Check whether the CSS Module can be used normally
  • Whether the generated style file Flex after build has a compatible prefix

Configuration JS

Compatible ES6 +

Download the required third-party packages:

Babel-loader: Used to process ES6+ syntax and compile it into JS that the browser can execute

@babel/core: Babel requires dependencies

@babel/preset-env: is a set of ES6 preset plugins that choose new features that are not supported by the target browser environment (Browserslist) to preload, which reduces unnecessary preversions and speeds up packaging

@ Babel/plugin – transform – runtime: It provides ES6+ API, such as the new ES6 array method, and so on. Unlike @babel/polyfill, this package can be loaded on demand.

@babel/runtime-corejs3: equivalent to @babel/polyfill. After 7.4.0, Babel uses runtime-core instead of Babel /polyfill

By default, Babel only converts new JS syntax, not new apis, such as Iterator, Generator, Set, Maps, Proxy, Reflect, Symbol, Promise, etc. And methods on global objects, such as Object.assign, will not be transcoded. (If ES6 adds array. form to Array, Babel will not transcode this method. You must use babel-polyfill, babel-Runtime, plugin-transform-Runtime, etc.)

Yarn add [email protected] yarn add @babel/[email protected] yarn add @babel/[email protected] yarn add @ Babel/[email protected] yarn add @ Babel/[email protected]Copy the code

During compilation, Babel reads the configuration (which is essentially a JSON file) from the.babelrc file in the project root directory, so you need to create a new file in the project root directory.

{
  "presets": [["@babel/preset-env",
      {
        "modules": false}]],"plugins": [["@babel/plugin-transform-runtime",
      {
        "corejs": {
          "version": 3."proposals": true}}]]}Copy the code

Presets: A collection of Plugins that tell Babel which new syntaxal features are being used in the source code to be converted, thus eliminating the need to write multiple Plugins

@ Babel/preset – env configuration:

  • Modules: Converts ES6+ module syntax to another type, default auto, to prevent Babel from translating any module type to CommonJS, causing tree-shaking failure

@ Babel/plugin – transform – the runtime configuration:

  • Corejs: dependency packageruntime-corejsIs used hereruntime-corejs3For the version information, set version to 3, and the default values are false. 3 are optional for the proxy to pollute global variables

Add js files to Webpack (for compatibility with TS and TSX)

// scripts/config/webpack.common.js
module.exports = {
  module: {
    rules: [{test: /\.(tsx? |js)$/,
        loader: 'babel-loader'.options: { cacheDirectory: true },
        exclude: /node_modules/,},// other...]},... }Copy the code

CacheDirectory: Babel-loader may generate duplicate public files during runtime, resulting in large volume of redundant code and slow compilation efficiency. Therefore, enabling this configuration to cache these public files will make the next compilation much faster

Exclude: third-party packages do not need to be translated. Exclude the packages to speed up packaging


Support the React

Download the required third-party packages:

React: React core dependencies

React -dom: handles dom rendering on the Web side

@types/react: React type declaration file for TSX

@types/react-dom: react-dom type declaration file used for TSX

@babel/preset- React: Used to preset Babel to translate JSX syntax

Yarn add [email protected] yarn add [email protected] yarn add @types/[email protected] yarn add @types/[email protected] yarn add @ Babel/[email protected]Copy the code

Babel-related configurations need to be configured in.babelrc

// .babelrc
{
  "presets": [["@babel/preset-env",
      {
        "modules": false}]."@babel/preset-react"],... }Copy the code

Note that @babel/preset-react should be preset to @babel/preset-env, indicating that JSX will be processed to ES6+ JS first. ES6+ JS is then processed to mean a block of JS code that the target browser can recognize


Support the Typescript

Download the required third-party packages

Typescript: Supports TS

@babel/preset-typescript: Ts files are processed by stripping the TS type declaration and compiling with other Babel plug-ins

Yarn add [email protected] yarn add @babel/[email protected]Copy the code

The same goes for.babelrc

// .babelrc
{
  "presets": [["@babel/preset-env",
      {
        "modules": false}]."@babel/preset-react"."@babel/preset-typescript"],}Copy the code

To use ts, you need to configure tsconfig.json in the root directory of your project, so create a new file and configure it (also generated by NPX TSC –init).

{
  "compilerOptions": {
    // Basic configuration
    "target": "ES5".// to which version of es is compiled
    "module": "ESNext".// Specify which module system code to generate
    "lib": ["dom"."dom.iterable"."esnext"].// A list of library files that need to be imported during compilation
    "allowJs": true.// Allow compiling js files
    "jsx": "react".JSX is supported in.tsx files
    "isolatedModules": true.// Provide some additional syntax checks, such as files without module export will report an error
    "strict": true.// Enable all strict type checking options

    // Module parsing options
    "moduleResolution": "node".// Specify the module resolution policy
    "esModuleInterop": true.Support interoperability between CommonJS and ES modules
    "resolveJsonModule": true.// Support to import JSON modules
    "baseUrl": ". /"./ / root path
    "paths": {								  // Pathmap, associated with baseUrl
      "src/*": ["src/*"]."components/*": ["src/components/*"]."utils/*": ["src/utils/*"]},// Experimental options
    "experimentalDecorators": true.// Enable experimental ES decorator
    "emitDecoratorMetadata": true.// Add design-type metadata to the decorator declaration in the source code

    // Other options
    "forceConsistentCasingInFileNames": true.Disallow inconsistent references to the same file
    "skipLibCheck": true.// Ignore type checking for all declaration files (*.d.ts)
    "allowSyntheticDefaultImports": true.// Allow default imports from modules that do not have default exports set
    "noEmit": true							  // You only want to use TSC's type checking as a function (when other tools (such as Babel actually compile) use it)
  },
  "exclude": ["node_modules"]}Copy the code

CompilerOptions: configure compilerOptions

  • BaseUrl and Paths: Used to quickly locate a file, preventing multiple layers. /.. /.. /..., baseUrl is set to. /Represents the root path of the projectbaseUrl/pathPath mapping, as configured above"components/*": ["src/components/*"]It’s essentially the same thing as taking/src/componentsThis path maps toComponentsSo,import xxx from '/src/components/xxx'The equivalent ofimport xxx from coponents/xxx, there are only three here at present. If necessary, you can come back here to continue to configure

BaseUrl and Paths need to be used in conjunction with webPack’s resolve. Alias attribute, and their configuration should be consistent. In fact, only in Webpack can complete the mapping, but also in tsconfig.json can add code intelligence hints

// scripts/config/webpack.common.js
module.exports = {
  // other...
  resolve: {
    alias: {
      'src': path.resolve(PROJECT_PATH, './src'),
      'components': path.resolve(PROJECT_PATH, './src/components'),
      'utils': path.resolve(PROJECT_PATH, './src/utils'),}}}Copy the code

Resolve: Configure webpack to find the file corresponding to the module.

  • Alias: The configuration item uses an alias to map the original import path to a new import path

You can create folders with the above paths to try out the effect

The CSS module import style from ‘./index.scss’ is not found./index.scss or its corresponding type declaration. Therefore, you need to write the declaration type file manually, create the typings directory in the SRC directory, and create the file.d.ts file

// src/typings/file.d.ts
declare module "*.css" {
  const style: any;
  export default style
}

declare module "*.scss" {
  const style: any;
  export default style
}

declare module "*.less" {
  const style: any;
  export default style
}
Copy the code

To optimize the

Omit file name extensions

Webpack can find and process files without the suffix

import App from './app.tsx'		/ / before processing
import App from './app'			/ / after processing
Copy the code

This needs to be configured in webpack’s resolve.Extensions

// scripts/config/webpack.common.js
module.exports = {
  // other...
  resolve: {
    extensions: ['.tsx'.'.ts'.'.js'.'.json',}}Copy the code

Extensions: The extensions are used to configure the list of suffixes to be used during the attempt. Webpack processes the files in the order defined by the extensions, and tries to put the most commonly used suffixes first. Can shorten the search time

Js compressed

Terser-webpack-plugin: Use to remove useless JS code in production environment. Webpack5 comes with webpack5, no need to install it separately

// scripts/config/webpack.prod.js
const TerserPlugin = require("terser-webpack-plugin")

module.exports = merge(common, {
  optimization: {
    minimize: true.minimizer: [new TerserPlugin({
        extractComments: false.terserOptions: {
          compress: { pure_funcs: ['console.log']},}}),]}})Copy the code

ExtractComments: Set to false to remove all comments except those with a special flag such as the @Preserve flag

Pure_funcs: Remove functions, as the above configuration means to remove all console.log functions

Package Type Check

At present, there is no type check information when webpack is packaged (for compilation speed, Babel does not check the type of TS when compiling ts), even if the type is not correct, the terminal will show the packaging success, which is misleading, so add package type check, download third-party package:

Fork-ts-checker-webpack-plugin: TS type checking so that the terminal can display type errors

Yarn add [email protected]Copy the code
// scripts/config/webpack.common.js
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
module.exports = {
  / /... other
  plugins: [
    new ForkTsCheckerWebpackPlugin({
      typescript: {
        configFile: path.resolve(PROJECT_PATH, './tsconfig.json'),},}),],}Copy the code

Stage of testing

Note that you are using TSX at this point, so you need to go back to Webpack and change the entry file from JS to TSX

// src/index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import App from './app'

if (module && module.hot) {
  module.hot.accept();
}

ReactDOM.render(
  <App />.document.querySelector('#root'))Copy the code
// src/app.tsx
import React from 'react'
import style from './app.scss'
import Test from 'components/Test'

const App:React.FC<any> = () = > {
  return (
    <div className={style.app}>
      <Test name='jack' age={24} />
    </div>)}export default App
Copy the code
// src/app.scss
.app {
  background-color: rgba(66.91.235.0.87);
  display: flex;
}
Copy the code
// src/components/Test/tsx
import React from 'react'

interface ITestProps {
  name: string
  age: number

}

const Test: React.FC<ITestProps> = ({name, age}) = > (
  <div>I am{name}, {age}!!!</div>
)

export default Test
Copy the code

Checkpoint:

  • Whether ES6+ syntax is available
  • React syntax is available
  • Ts functions are normal

Configuration of resources

Supported file formats

Webpack5 has built-in resource modules, so there is no need to download file-loader and url-loader.

// scripts/config/webpack.common.js
module.exports = {
  module: {
    rules: [{test: [/\.bmp$/./\.gif$/./\.jpe?g$/./\.png$/].type: 'asset'.parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024,},},}, {test: /\.(eot|svg|ttf|woff|woff2?) $/,
        type: 'asset/resource',},]}}Copy the code

Type: indicates the resource module type

  • ‘asset/ Resource: Splits resources into separate files and exports urls, which is what file-loader used to do
  • Asset /inline: Export the resource as a dataURL (URL (data:)), the previous urL-loader function
  • Asset /source: Export the resource as source code. Previous raw-loader functionality
  • Asset: automatically selects export as a separate file or dataURL (default: 8KB). Previously, urL-loader set asset Size limit to restrict implementation

DataUrlCondition: Specifies the resource size in bytes

In order to specify the packing catalog, you need to configure the packing exit of the production environment

// scripts/config/webpack.prod.js
module.exports = merge(common, {
  output: {
    / /... other
    assetModuleFilename: 'images/[name].[contenthash:8].[ext]',}})Copy the code

Because you are using TS, importing the file suffix above will produce a non-existent error, so continue adding the declaration file

// src/typings/file.d.ts
declare module '*.svg' {
  const path: string
  export default path
}

declare module '*.bmp' {
  const path: string
  export default path
}

declare module '*.gif' {
  const path: string
  export default path
}

declare module '*.jpg' {
  const path: string
  export default path
}

declare module '*.jpeg' {
  const path: string
  export default path
}

declare module '*.png' {
  const path: string
  export default path
}
Copy the code

Working with static Resources

To place non-imported resources used in JS files in the package directory (such as static resources under public), you need to download third-party packages

Copy-webpack-plugin: Handles static resource files that do not need to be dynamically imported and copies them into the package directory

Yarn add [email protected]Copy the code
// scripts/config/webpack.common.js
module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [{context: 'public'.from: The '*'.to: path.resolve(PROJECT_PATH, './dist/public'), 
          toType: 'dir'.globOptions: {
            dot: true.gitignore: true.ignore: ['**/index.html'].// ** indicates any directory},},],})]}Copy the code

Content: Explains the FRON path. The specific function is unknown

From: Defines the source file to copy

To: Defines the specified path for pasting

ToType: Determines the type of the paste path. Dir indicates that the path is a folder

GlobOptions: allows global matching


Webpack optimization

Clear packaged data

Prevent file accumulation caused by multiple builds

Download third-party packages:

Clean-webpack-plugin: Cleans up the contents of the last packed dist directory to prevent file residues

Yarn add [email protected]Copy the code
// scripts/config/webpack.common.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

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

Caching mechanisms

This feature is built into webpack5.

// scripts/config/webpack.common.js
module.exports = {
  cache: {
    type: 'filesystem'.buildDependencies: {
      config: [__filename],
    },
  },
}
Copy the code

Cache. type: indicates the cache type. The value can be memory or filesystem, representing the memory based temporary cache and filesystem based persistent cache respectively

Cache. buildDependencies: A mechanism for global cache invalidation. {config: [__filename]} indicates that the current build cache is invalidated when the contents of the configuration file or the module file on which the configuration file depends change

When the module code does not change, but the build process itself changes (for example, the Webpack version is upgraded, configuration files are modified, environment variables are changed, and so on), it can also affect the post-build production code. So you can't reuse previously cached data in this case, but you need to invalidate the global cache, rebuild and generate a new cacheCopy the code

The code segment

When written lazily, WebPack automatically splits the code into chunks

Benefits:

  • If an imported component is loaded lazily, the package name is not changed if the component code is unchanged. After the component is deployed in the production environment, users do not need to download the file again because of browser cache, shortening the web interaction time
  • Prevent all components into a package, reducing the first screen time
// this is a lazy way to write
import("./xxx").then(module= > {
  console.log(module.foo())
})

// React. Lazy
const MyComponent = React.lazy(() = > import('Components/MyComponent'))
Copy the code

Code splitting is enabled by default in Webpack, but additional configuration is required in WebPack to package third-party dependencies as separate chunks

// scripts/config/webpack.dev.js
module.exports = merge(common, {
  optimization: {
    minimize: false.minimizer: [].splitChunks: {
      chunks: 'all'.minSize: 0,}}})Copy the code
// scripts/config/webpack.prod.js
module.exports = merge(common, {
  optimization: {
	/ /... other
    splitChunks: {
      chunks: 'all'.minSize: 0,}}})Copy the code

SplitChunks: code segmentation configuration

Splitchunks. chunks: Choose what to optimize for. All indicates that even synchronous and asynchronous code can share thunk

MinSize: Minimum size (in bytes) of chunk to be generated


Problems and Solutions

Version of the problem

Error message Cannot find module ‘webpack/bin/config-yargs

Problem: Webpack-CLI and webpack-dev-server have version compatibility issues that cause packaging errors

Solution: A unified version, such as 3.x, is used in this project