This article describes how to build a React scaffolding from scratch, including how to add Redux and the React Router environment.

This article code address:react-mobx-starter.

It is recommended that you pull down the code and view it together with this article for better results.

Code download command:

git clone -b example https://github.com/beichensky/react-mobx-starter.git
Copy the code

The Babel configuration in scaffolding was recently updated to version 7.0.0, so some changes have been made. The current versions of various libraries in scaffolding are as follows:

  • Node: 10.15.3
  • NPM: 6.4.1
  • Webpack: 4.29.6
  • Webpack – cli: 3.3.0
  • Webpack dev – server: 3.1.4
  • @ Babel/core: 7.0.0
  • React: 16.8.6
  • Mobx: 5.9.4
  • The react – the router – dom: 5.0.0

If you are upgrading from a lower version to 7.0.0, there is a new command that can directly help you update the project:

npx babel-upgrade --write --install
Copy the code

More information about Babel-upgrade can be found in the official instructions.


Previously on

The Demo in this article is divided into two environments, one for development and the other for production.

  • Development environment is about how to configure a better, more convenient development environment;

  • Production is about configuring a more optimized, smaller version of the production environment.

I’ve written several articles on the use of Webpack before, and this article builds on Webpack and expands on previous code.

  • The development environment configuration is an extension of the Webpack development environment configuration from scratch (with Demo).

  • Production environment configuration is an extension of the production environment configuration using Webpack (with Demo) article.

Suggestion: for friends who do not know Webpack, you can first look at the two articles: build a Webpack development environment configuration from scratch (with Demo) and use Webpack for production environment configuration (with Demo), you can better start with this article.

Although this article is an extension of the previous article, it will go through the configuration of each step in detail.


Create a project structure

Create a folder named react-Mox-Starter

mkdir react-mobx-starter 
Copy the code

Initialize the package.json file

cd react-mobx-starter

# Generate the default package.json file directly
npm init -y
Copy the code

We’re going to create a SRC directory to hold the code that we’re writing and we’re going to create a public directory to hold the public files and we’re going to create a Webpack directory to hold the WebPack configuration files

mkdir src

mkdir public

mkdir webpack
Copy the code

Create a Pages folder in the SRC directory for your written page components. Create a Components folder for your public components. Create a utils folder for your common utility classes

cd src

mkdir pages

mkdir components

mkdir utils
Copy the code

Create an index. HTML file in the public directory. Create an index.js file in the SRC directory. Create webpack.config.dev.js and webpack.config.prod.js in the webpack directory

  • webpack.config.dev.jsUsed to write the WebPack development environment configuration
  • webpack.config.prod.jsUsed to write the WebPack production environment configuration

index.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 + Mobx family bucket scaffolding</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>
Copy the code

index.js

function createElement() {
    const ele = document.createElement('div');
    ele.innerHTML = 'Hello, React';
    const root = document.querySelector('#root');
    root.appendChild(ele);
}

createElement();
Copy the code

Webpack.config.dev. js and webpack.config.prod.js are not written at this point, but we’ll cover them in more detail later.

Let’s take a look at the project structure at this point, and then we can configure WebPack.

├─ ├─ exercises, ├─ exercises, exercises, exercises, exercises, exercises, exercises, exercises Webpack. Config. Dev. Js └ ─ webpack. Config. Prod. Js ├ ─ package. The jsonCopy the code

Configure the React development environment

Add an execution script to the package.json file to execute the webpack command:

{
    ...,
    "scripts": {
        "start": "webpack --config webpack/webpack.config.dev.js"
    },
    ...
}
Copy the code

Install webPack-related plug-ins

Install Webpack and WebPack-CLI

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

Entrance and exit

When configuring a project using WebPack, there must be an entry and an exit, as module entry and project output.

webpack.config.dev.js

const path = require('path');

const appSrc = path.resolve(__dirname, '.. /src');
const appDist = path.resolve(__dirname, '.. /dist');
const appPublic = path.resolve(__dirname, '.. /public');
const appIndex = path.resolve(appSrc, 'index.js');

module.exports = {
    entry: appIndex,
    output: {
        filename: 'public/js/[name].[hash:8].js'.path: appDist,
        publicPath: '/'}}Copy the code

Add htML-webpack-plugin

Dist /public/js file, but this file is named by the hash value. It is too much trouble to manually import it into the index.html file each time. So the HTML-webpack-plugin can be introduced.

The HTML-webpack-plugin serves two purposes

  • Can bepublicCopy the folder under the directory todistOutput folder
  • Can automaticallydistUnder thejsFile import intohtmlIn the file

The installationhtml-webpack-pluginThe plug-in

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

usehtml-webpack-pluginThe plug-in

webpack.config.dev.js


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

const appSrc = path.resolve(__dirname, '.. /src');
const appDist = path.resolve(__dirname, '.. /dist');
const appPublic = path.resolve(__dirname, '.. /public');
const appIndex = path.resolve(appSrc, 'index.js');
+ const appHtml = path.resolve(appPublic, 'index.html');

module.exports = {
    entry: appIndex,
    output: {
        filename: 'public/js/[name].[hash:8].js'.path: appDist,
        publicPath: '/'
    },
+    plugins: [
+        new HTMLWebpackPlugin({
+            template: appHtml,
+            filename: 'index.html'+}) +]}Copy the code

Setting development Mode

The mode property in the Webpack configuration can be set to ‘development’ and ‘production’. We are currently in the development environment configuration, so it can be set to ‘development’.

webpack.config.dev.js

. module.exports = { + mode:'development'. }Copy the code

Set the devtool

In order to quickly locate the error in the project, you can set devtool to generate the resource map. We use inline-source-map here. For more options, see the difference here.

webpack.config.dev.js

. module.exports = {mode: 'development',
+    devtool: 'inline-source-map'. }Copy the code

Start the project service with webpack-dev-server

Webpack – dev – server installation

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

Configuration webpack – dev – server

webpack.config.dev.js

. module.exports = {mode: 'development'.devtool: 'inline-source-map',
+    devServer: {
+        contentBase: appPublic,
+        hot: true,
+        host: 'localhost',
+        port: 8000,
+        historyApiFallback: true,
+        // Whether to display errors in the browser mask
+        overlay: true,
+        inline: true,
+        // Prints information
+        stats: 'errors-only',
+        // Set the proxy
+        proxy: {
+            '/api': {
+                changeOrigin: true,
+                target: 'https://easy-mock.com/mock/5c2dc9665cfaa5209116fa40/example',
+                pathRewrite: {
+                    '^/api/': '/'+} +} +} +},... }Copy the code

Modify the start script in package.json:

{
    ...,
    "scripts": {
        "start": "webpack-dev-server --config webpack/webpack.config.dev.js"
    },
    ...
}
Copy the code

Use the friendly-errors-webpack-plugin

The friendly-errors-webpack-plugin can display better prompt functionality on the command line.

Install the friendly – errors – webpack – the plugin:

npm install friendly-errors-webpack-plugin --save-dev
Copy the code

Use friendly – errors – webpack – the plugin:

webpack.config.dev.js


const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
+ const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); . module.exports = { ... plugins: [new HTMLWebpackPlugin({
            template: appHtml,
            filename: 'index.html'+})new FriendlyErrorsWebpackPlugin(),
    ]
}
Copy the code

Enabling hot loading

webpack.config.dev.js

const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
+ const webpack = require('webpack'); . module.exports = { ... plugins: [ ... new FriendlyErrorsWebpackPlugin(), +new webpack.HotModuleReplacementPlugin()
    ]
}
Copy the code

Run the project and test the configuration

Run the NPM run start command. After a success message is displayed, open http://localhost:8000 and see Hello React.

Configure the Babel

Now we have less code in index.js, so no problem. However, if I want to use some ES6 syntax or JS features that are not yet defined by the standard, then I need to use Babel for conversion. Let’s configure Babel.

Install the Babel plug-in

npm install @babel/core babel-loader --save-dev
Copy the code

Use the Babel – loader

Sets the cacheDirectory property to be used to cache loader execution results. Subsequent WebPack builds will attempt to read the cache to avoid the potentially high-performance Babel recompilation process that can occur each time it is executed.

webpack.config.dev.js

. module.exports = { ... plugins: [ ... ] .module: {
        rules: [{test: /\.(js|jsx)$/.loader: 'babel-loader? cacheDirectory'.include: [ appSrc ],
                exclude: /node_modules/}}}]Copy the code

Create a new babel.config.js file in the project root directory

The babel.config.js file is a runtime control file that automatically reads the Babel configuration in the babel.config.js file when the project is compiled.

Use Babel related Presets

Install related plug-ins:

  • @babel/preset-env: You can use all of them in a projectECMAScriptThe latest features in the standard.
  • @babel/preset-react: Can be used in projectsreactSyntax.
npm install babel-preset-env babel-preset-react --save-dev
Copy the code

To configure the babel.config.js file:

module.exports = (api) = > {
    api.cache(true);

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

Use Babel-related plugins

After Babel is upgraded to version 7.0.0, @babel/preset-stage-0 is deprecated and the plugin used needs to be installed itself. If you are upgrading from a lower version to 7.0.0, there is a new command that can directly help you update the project:

npx babel-upgrade --write --install
Copy the code

More information about Babel-upgrade can be found in the official instructions.

Install related plug-ins:

  • @babel/plugin-proposal-decorators: Decorator syntax can be used in projects.
  • @babel/plugin-proposal-class-properties: You can use the new class attribute syntax in your project.
  • @babel/plugin-transform-runtime: Use this plug-in to directly use the code pairs in Babel-RuntimejsFiles are converted to avoid code redundancy.
  • @babel/runtime-corejs2: cooperate withbabel-plugin-transform-runtimePlug-ins in pairs
  • @babel/plugin-syntax-dynamic-import: Can be used in projectsimport()This syntax
  • @babel/plugin-proposal-export-namespace-from: Modules can be exported using the namespace export *
  • @babel/plugin-proposal-throw-expressions: You can throw an expression with an exception
  • @babel/plugin-proposal-logical-assignment-operators: Logical assignment operators can be used
  • @babel/plugin-proposal-optional-chainingCan you access deeply nested properties or functions using optional chains? .
  • @babel/plugin-proposal-pipeline-operator: you can use the pipeline operator | >
  • @babel/plugin-proposal-nullish-coalescing-operatorCan use null value merge syntax?
  • @babel/plugin-proposal-do-expressions: You can use the DO expression (think of it as a more complex version of the ternary operator)
  • @babel/plugin-proposal-function-bind: You can use the function binding syntax obj::func
npm install @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime @babel/runtime-corejs2 @babel/plugin-syntax-dynamic-import @babel/plugin-proposal-export-namespace-from @babel/plugin-proposal-throw-expressions @babel/plugin-proposal-logical-assignment-operators @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-pipeline-operator @babel/plugin-proposal-nullish-coalescing-operator @babel/plugin-proposal-do-expressions @babel/plugin-proposal-function-bind --save-dev
Copy the code

To configure the babel.config.js file:

module.exports = (api) = > {
    api.cache(true);

    return {
        presets: [
            "@babel/preset-env"."@babel/preset-react"].plugins: [["@babel/plugin-proposal-decorators",
                {
                    "legacy": true}], ["@babel/plugin-transform-runtime",
                {
                    "corejs": 2}], ["@babel/plugin-proposal-class-properties", 
                { 
                    "loose": true}]."@babel/plugin-syntax-dynamic-import".// Modules can be exported using the namespace export *
            "@babel/plugin-proposal-export-namespace-from".// You can throw an expression with an exception,
            "@babel/plugin-proposal-throw-expressions".// Export by default
            "@babel/plugin-proposal-export-default-from".// Logical assignment operators can be used
            "@babel/plugin-proposal-logical-assignment-operators".// Can you access deeply nested properties or functions using an optional chain? .
            "@babel/plugin-proposal-optional-chaining"./ / you can use the pipeline operator | >
            [
                "@babel/plugin-proposal-pipeline-operator",
                {
                    "proposal": "minimal"}].// Can use null value merge syntax??
            "@babel/plugin-proposal-nullish-coalescing-operator".// You can use the do expression (think of it as a complicated version of the ternary operator)
            "@babel/plugin-proposal-do-expressions".// You can use the function binding syntax obj::func
            "@babel/plugin-proposal-function-bind"]}}Copy the code

Note the order in which the @babel/plugin-proposal-decorators plugins are placed, preferably first, otherwise some annotations may fail.

At this point, the basic configuration for Babel is complete. Then we can use all the new JS features in our projects.

Add a LOADER related to the CSS

Js file related babel-loader is configured, but sometimes we want to add styles to elements in a project, and webpack considers everything to be a module, so we need other loaders to parse a wave of style code.

Install related plug-ins:

  • css-loader: handlingcssIn the fileurl()And so on.
  • style-loaderWill:cssInserted into the pagestyleThe label.
  • less-loader: is tolessFile compiled intocss.
  • postcss-loader: can integrate many plug-ins, used for operationcss. We use it here for integrationautoprefixerTo automatically add prefixes.
npm install css-loader style-loader less less-loader postcss-loader autoprefixer --save-dev
Copy the code

Configure the style dependent Loader

  • Due to theReactCannot be used directly similarVuescopeThis local effect variable, so we can usewebpackTo provide theCSS Module. 2, because it will be used laterantd, so introducingantdNeed to be turned onlessjavascriptChoice, so you want to putless-loaderThe properties in thejavascriptEnabledSet totrue.

Configure in webpack.config.dev.js:

. const autoprefixer =require('autoprefixer');

module.exports = { ... .plugins: [...]. .module: {
        rules: [..., {test: /\.(css|less)$/.exclude: /node_modules/.use: [{
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader'.options: {
                            sourceMap: true.modules: true.localIdentName: '[local].[hash:8]'}}, {loader: 'postcss-loader'.options: {
                            plugins: (a)= > [autoprefixer()]
                        }
                    },
                    {
                        loader: 'less-loader'.options: {
                            javascriptEnabled: true}}]}, {test: /\.(css|less)$/.include: /node_modules/.use: [{
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader'.options: {}}, {loader: 'postcss-loader'.options: {
                            plugins: (a)= > [autoprefixer()]
                        }
                    },
                    {
                        loader: 'less-loader'.options: {
                            javascriptEnabled: true}}]},]}}Copy the code

Add other modules to parse loader configurations

Install related plug-ins:

npm install file-loader csv-loader xml-loader html-loader markdown-loader --save-dev
Copy the code

Configure in webpack.config.dev.js:

. module.exports = { ... .plugins: [...]. .module: {
        rules: [...// Parse image resources
            {
                test: /\.(png|svg|jpg|gif)$/.use: [
                    'file-loader']},// Parse the font
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/.use: [
                    'file-loader']},// Parse data resources
            {
                test: /\.(csv|tsv)$/.use: [
                    'csv-loader']},// Parse data resources
            {
                test: /\.xml$/.use: [
                    'xml-loader']},// Parse the MakeDown file
            {
                test: /\.md$/.use: [
                    'html-loader'.'markdown-loader'}]}}Copy the code

Additional WebPack configuration optimization

Add the Resolve Allias attribute and set the alias

The alias attribute in Resolve can be used to alias common folders. If the alias attribute in Resolve is used to alias common folders, the alias attribute in Resolve can be used to alias common folders

webpack.config.dev.js

...module.exports = { ... .plugins: [...]. .module: {... }, + resolve: { + alias: { + src: appSrc, + utils: path.resolve(__dirname,'.. /src/utils'),
+            pages: path.resolve(__dirname, '.. /src/pages'),
+            components: path.resolve(__dirname, '.. /src/components'+} +}}Copy the code

Add the resolve.modules attribute to specify where third-party modules will be stored

As we know, when searching for modules, node_modules in the current directory will be searched all the way to node_modules in the disk root directory. So to reduce the search steps, we can set the resolve.modules property to force only looking up modules from the project’s node_modules.

webpack.config.dev.js

...module.exports = { ... .plugins: [...]. .module: {... },resolve: {
        ...,
+        modules: [path.resolve(__dirname, '.. /node_modules')].}}Copy the code

Install React, MObx, and React Router plugins

npm install react react-dom prop-types mobx mobx-react react-router-dom --save
Copy the code

The introduction of antd

Follow the instructions on antD’s website to add the configuration directly to the babel.config.js file and then it will be used normally in the project.

Install antD plug-ins:

npm install antd moment --save
Copy the code

Install babel-plugin-import to load components on demand:

npm install babel-plugin-import --save-dev
Copy the code

Add antD configuration to babel.config.js:

module.exports = (api) = > {
    api.cache(true);
    
    return {
        presets: [...]. .plugins: [..., + [+"import", + {+"libraryName": "antd",
    +                "style": true+} +],... ] }Copy the code

React development

Basically all the necessary plug-ins have been introduced so it’s time to develop.

Modify the index.js file in the root directory

index.js

import React from 'react';
import ReactDom from 'react-dom';
import { Provider } from 'mobx-react'
import { LocaleProvider } from 'antd';
import { HashRouter } from 'react-router-dom';
import zh_CN from 'antd/lib/locale-provider/zh_CN';
import 'moment/locale/zh-cn';

import GlobalModel from './GlobalModel';
// import App from './App';

const globalModel = new GlobalModel();

const App = (a)= > {
    return <div>The development environment is configured</div>
}

ReactDom.render(
    <Provider globalModel={ globalModel} >
        <LocaleProvider locale={zh_CN}>
            <HashRouter>
                <App />
            </HashRouter>
        </LocaleProvider>
    </Provider>.document.querySelector('#root'));Copy the code

Run the NPM run start command and open http://localhost:8000/ in the browser. You can see that the configuration of the development environment is complete.

At this point, it shows that our various plug-ins and libraries have been introduced and can be used normally.

Use React Route to redirect routes between pages

Create app.js file in SRC directory:

App.js

import React from 'react';
import { Switch, Route } from 'react-router-dom';

import Home from 'pages/home';
import Settings from 'pages/settings';
import Display from 'pages/display';
import NotFound from 'pages/exception'

import styles from './App.less';


export default (props) => {
    return (
        <div className={ styles.app }>
            <Switch>
                <Route path='/settings' component={ Settings } />
                <Route path='/display' component={ Display } />
                <Route exact path='/' component={ Home } />
                <Route component={ NotFound } />
            </Switch>
        </div>
    )
}
Copy the code

Create an app.less file in the SRC directory and style your App components

App.less

.app {
    padding: 60px;
}
Copy the code

Write Home, Settings, Display, NotFound components in the Pages directory

  • HomeComponent is the root routing component used to jump toSettingInterface andDisplayinterface
  • SettingsDoes the component demonstrate how to obtain and modify itmobxThe globalModel
  • DisplayThe component demonstrates how to use Mobx for synchronous and asynchronous data processing
  • NotFoundComponent is displayed when the correct route is not matched

I’m not going to post the code for Home, Settings, Display, it’s a long one, but if you need it, you can go to Github and take a look at it or download it. It’s convenient. Address: making

Modify the index.js file again

index.js

import React from 'react';
import ReactDom from 'react-dom';
import { Provider } from 'mobx-react'
import { LocaleProvider } from 'antd';
import { HashRouter } from 'react-router-dom';
import zh_CN from 'antd/lib/locale-provider/zh_CN';
import 'moment/locale/zh-cn';

import GlobalModel from './GlobalModel';
import App from './App';

const globalModel = new GlobalModel();

ReactDom.render(
    <Provider globalModel={ globalModel} >
        <LocaleProvider locale={zh_CN}>
            <HashRouter>
                <App />
            </HashRouter>
        </LocaleProvider>
    </Provider>.document.querySelector('#root'));Copy the code

As you can see, there is a GlobalModel that holds the global universal data. The logic inside is relatively simple, so let’s take a look at it a little bit.

GlobalModel.js

import { observable, action } from 'mobx';

export default class GlobalModel {
    @observable username = 'Ming';

    @action
    changeUserName = (name) = > {
        this.username = name; }}Copy the code

Add the FETCH utility class for network requests

Since we need to carry out asynchronous operation of network request in Display component, fetch is introduced here for network request.

Install fetch related plug-ins:

npm install whatwg-fetch qs --save
Copy the code

Write the network request utility class

Create the request.js file in the utils directory.

utils/request.js

import 'whatwg-fetch';
import { stringify } from 'qs';

* @param {*} url * @param {*} data */
export const get = (url, data) = > {
    const newUrl = url + '? ' + stringify(data) + (stringify(data) === ' ' ? ' ' : '&') +'_random=' + Date.now();
    return fetch(newUrl, {
            cache: 'no-cache'.headers: {
                'Accept': 'application/json'.'Content-Type': 'application/json; charset=utf-8'
            },
            method: 'GET',
        })
        .then(response= > response.json());
}

* @param {*} url * @param {*} data */
export const post = (url, data) = > {
    return fetch(url, {
        body: JSON.stringify(data), 
        cache: 'no-cache'.headers: {
            'Accept': 'application/json'.'Content-Type': 'application/json; charset=utf-8'
        },
        method: 'POST',
    })
    .then(response= > response.json()) // parses response to JSON
}
Copy the code

At this point, the simple React framework is complete

After executing NPM run start, you can see that the interface looks like this.

The Home interface:

Settings interface:

The Display interface:

NotFound interface:


5. Configure React project packaging

Json file to add an execution script:

{
    ...,
    "scripts": {
        "start": "webpack-dev-server --config webpack/webpack.config.dev.js",
        "build": "webpack --config webpack/webpack.config.prod.js"
    },
    ...
}
Copy the code

Configure the webpack.config.prod.js file

Most of these modules and Plugins and resolve are consistent with the development environment. So let’s start with the configuration in the webpack.config.dev.js file.

  • Change the mode property value to: ‘production’
  • Change the devTool property value to ‘hidden-source-map’
  • Delete all configuration of the devServer property.
  • Delete the use of thermal loading plug-ins: · webpack. HotModuleReplacementPlugin `,

Add the optimization attribute for code compression

Install related plug-ins:

npm install uglifyjs-webpack-plugin optimize-css-assets-webpack-plugin --save-dev
Copy the code

Add code compression configuration:

webpack.config.prod.js

. ;const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); . ;module.exports = {
    mode: 'production'.devtool: 'hidden-source-map'.entry:... .output: {... },plugins: [...]. .module: {... },optimization: {
        // Package compressed js/ CSS files
        minimizer: [
            new UglifyJsPlugin({
                uglifyOptions: {
                    compress: {
                        // UglifyJs deletes unused code without warning
                        warnings: false.// Delete all 'console' statements, compatible with Internet Explorer
                        drop_console: true.// Inline variables that are defined but used only once
                        collapse_vars: true.// Extract static values that occur multiple times but are not defined as variables to reference
                        reduce_vars: true,},output: {
                        // Most compact output
                        beautify: false.// Delete all comments
                        comments: false,}}}),new OptimizeCSSAssetsPlugin({})
        ],
        splitChunks: {
            cacheGroups: {
                styles: {
                    name: 'styles'.test: /\.(css|less)/.chunks: 'all'.enforce: true.reuseExistingChunk: true // Indicates whether to use the existing chunk. True indicates that if the chunk contains modules that have been extracted, no new chunk will be generated.
                },
                commons: {
                    name: 'commons'.chunks: 'initial'.minChunks: 2.reuseExistingChunk: true
                },
                vendors: {
                    name: 'vendors'.test: /[\\/]node_modules[\\/]/.priority: - 10.reuseExistingChunk: true}}},runtimeChunk: true
    },
    resolve: {...}
}
Copy the code

Extract CSS code using the mini-CSs-extract-plugin

Install related plug-ins:

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

Configure the mini-CSS-extract-plugin plugin:

  • inpluginsProperty to introduce
  • willmodulerulesUsed in thestyle-loaderReplace withMiniCssExtractPlugin.loader

webpack.config.prod.js

. const MiniCssExtractPlugin =require('mini-css-extract-plugin');

module.exports = { ... .plugins: [...new MiniCssExtractPlugin({
            filename: 'public/styles/[name].[contenthash:8].css'.chunkFilename: 'public/styles/[name].[contenthash:8].chunk.css'})].modules: {
        rules: [..., {test: /\.(css|less)$/.exclude: /node_modules/.use: [
                    {
-                        loader: 'style-loader'
+                        loader: MiniCssExtractPlugin.loader
                    },
                    ...
                ]
            },
            {
                test: /\.(css|less)$/.exclude: /node_modules/.use: [
                    {
-                        loader: 'style-loader'+ loader: MiniCssExtractPlugin.loader }, ... ] },... ] },... }Copy the code

Define the current production environment using the DefinePlugin plug-in

webpack.config.prod.js

. module.exports = { ... .plugins: [...new webpack.DefinePlugin({
            // Define the NODE_ENV environment variable as production
            'process.env': {
                NODE_ENV: JSON.stringify('production'}})],... }Copy the code

Clean up the dist directory using the clean-webpack-plugin

In the process of packaging, some file names used hash values, resulting in different files each time, so some redundant files were generated in DIST. So we can clean up the dist directory before each packing.

Install plug-in:

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

Using plug-ins:

webpack.config.prod.js

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

Add other optimization configurations

  • Add STATS to configure some statistics that appear when filtering packaging.
  • Add the Performance configuration to turn off the performance prompt

webpack.config.prod.js

module.exports = { ... .stats: {
        modules: false.children: false.chunks: false.chunkModules: false
    },
    performance: {
        hints: false}}Copy the code

Package the project for release

Packaging project

Run the NPM run build command. After the console is packaged, the dist folder is added to the root directory.

Publish projects using Nginx

Here I am using Nginx as the server, published locally.

Nginx download: nginx.org/en/download… .

Once the download is complete, the decompression is complete. Open the Nginx directory, find a conf folder, find the nginx.conf file, modify the configuration in the Nginx:

Change the HTML labeled in the figure to DIST.

We can then safely place the generated dist folder directly into the Nginx installation directory. (The dist directory should be the same as the conf directory).

Start Nginx service:

start nginx
Copy the code

Open your browser and type http://127.0.0.1 or http://localhost to see that our project is running properly.

Nginx other commands:

# Stop Nginx service
nginx -s stop

Restart the Nginx service
nginx -s reload

# exit nginx
nginx -s quit
Copy the code

For more information about Ngnix, please refer to: Nginx official documentation

Note: Nginx commands need to be executed under Nginx installation!


Use webpack-merge to introduce webPack common configuration

If you look at the webpack.config.dev.js and webpack.config.prod.js files, you can see a lot of code and configuration duplication. So we can write a webpack.common.js file and put our common configuration into it, The webpack-merge plug-in is then imported into the webpack.config.dev.js and webpack.config.prod.js files, respectively.

Plug-in installation:

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

Use:

+ const merge = require('webpack-merge');
+ const common = require('./webpack.common.js');

+ module.exports = merge(common, {
+   mode: 'production', +... +});Copy the code

Here is how to use webPack-merge. Due to the long space, I will not post the specific configuration code in the three files. You can check the configuration file after using Webpack-Merge on GitHub.


Seven, this article source address

react-mobx-starter

Welcome Star, thank you!

If there is any problem in the article and code, please correct it, thank you!


Viii. Reference documents

Webpack website

Build a Webpack environment configuration from scratch (with Demo)

Production environment configuration using Webpack (with Demo)