In the previous project, webPack3 was packaged with too much dependence, uglify plug-in was unavailable, imageloader plug-in was unavailable and so on. Therefore, whether to upgrade webPack3 of the original project to WebPack4 was considered first, and then more problems appeared. So finally consider building your own React front-end scaffolding from scratch.

  • Github address of this project:https://github.com/SHENLing0628/React-Webpack4-Scaffold
  • Reference documents for this article:https://juejin.cn/post/6844903862898262024#heading-28

1. Project Features

  • HMR: hot-module-replacement – When the application is in developer mode, it can directly replace the add-delete module without refreshing the page, avoiding the loss of previous operation data /state caused by refreshing the page;
  • happypack: Since webpack was originally packaged in a single thread execution, using the optimized happyPack mode can be used to execute the project building work in a multi-threaded manner. The default number of threads is three, which can be customized. This method is more friendly to large projects;
  • antd: Using the method of babel-plugin-import, by modifying the configuration in babelrc, introduce antD style, so that each component can directly use antD component library;

2. Principle explanation

  • Webpack is configured to quickly build projects and package projects, convenient for developers to implement development debugging and package project deployment

3. Detailed explanation of operation process

  1. Initialize the project (not using CRA)
mkdir react-webpack4-scaffold
cd react-webpack4-scaffold
mkdir src
mkdir dist
npm init -y
Copy the code
  1. Install react and react-router-dom
cd src 
cnpm i react react-router-dom -S
Copy the code

Create the following file structure (the last three WebPack configuration files will be explained in detail in the next step) :

| - SRC / / for deposit page source code file | | - API / / storage API interface link, To facilitate unified management | | | - index. The js | | - assets / / storing images, font file | | | - images' | | | - fonts | | - components/store/common components, Available for a number of different page reuse | | | - sampleComponent | | | | - index. The js | | | | - index. The SCSS | | - store pages / / page components | | | -- - the Main | | | | - index. Js | | | | - index. The SCSS | | - the router / / routing file, Used for different links to different pages component | | | - index. The js | | - utils / / deposit axios interface request configuration file | | - index. The js / / page entry | | - index. The HTML / / HTML page entry |--- webpack.config.base.js |--- webpack.dev.config.js |--- webpack.prod.config.jsCopy the code
  1. Install webpack, webpack-cli, webpack-dev-server.
npm install webpack webpack-cli webpack-dev-server -D
Copy the code

Then create three WebPack configuration files:

| - webpack. Config. Base. Js / / webpack general infrastructure | - webpack. Dev. Config. Js / / webpack in developer mode configuration (applicable to the development and debugging) | -- - Webpack.prod.config. js // The deployment mode of Webpack packages the configurationCopy the code

(1) webpack.config.base.js file details:

  • First, populate the basic WebPack configuration framework:
module.exports = {
    entry: ["./src/index.js"],
    output: {
        path: path.join(__dirname, "dist"),
    },
    module:{},
    plugins:[],
    devServer:{}
}
Copy the code

In the basic configuration, we need to set all the common configuration here, so we need to install a few plug-ins here:

  • Clean-webpack-plugin is used to clean old files in the packaged folder dist
  • Html-webpack-plugin is used to generate HTML by inserting packaged JS files into HTML or using custom templates to generate final HTML files
  • Happypack is used to implement multi-threaded packaging projects, which can improve efficiency when facing large projects
npm install clean-webpack-plugin html-webpack-plugin happypack -D
Copy the code
const path = require('path')
const babelpolyfill = require("babel-polyfill"Babel-polyfill const webpack = require('webpack')

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })

module.exports = {
    entry: ["./src/index.js"],
    output: {
        path: path.join(__dirname, "dist"),
    },
    module:{},
    plugins:[
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            filename: 'index.html'Template: path.join(__dirname,'./src/index.html'// Specify the template path favicon:path.resolve("./src/assets/images/logo.png"), // Logo minify: {collapseWhitespace:true}}), new HappyPack({// use the same ID as in rules for those files that are processed by HappyPack:'happyBabel',
            loaders: [{
                loader: 'babel-loader? cacheDirectory=true'}], // Share threadPool: HappyThreadPool is a shared process pool, that is, multiple instances of happyPack use the same process in the same process pool to process tasks, to prevent too many resources in threadPool: happyThreadPool, verbose:false// Allow happyPack to print logs})],}Copy the code

Now populate the other configuration sections

  • Alias section (after Output) – Easy to write code without thinking about relative paths:
resolve: {
    extensions: ['.js'.'.jsx'.'.scss'].alias: {
        src: path.resolve(__dirname, './src'),
        pages: path.resolve(__dirname, './src/pages'),
        router: path.resolve(__dirname, './src/router'),
        components: path.resolve(__dirname, './src/components'),
        serviceComponents: path.resolve(__dirname, './src/serviceComponents'),
        actions: path.resolve(__dirname, './src/actions'),
        api: path.resolve(__dirname, './src/api'),
        assets: path.resolve(__dirname, './src/assets')}},Copy the code
  • Package rule section (after Resolve above)
Module: {// Configure the compiler packaging rules.test: /\.(jsx|js)? $/, exclude: /node_modules/, use: [{// Use happypack with webpack4 for multi-threaded packaging, improve packaging efficiency, for large projects. // The id here must be the same as the id number defined in the above plugin.'happypack/loader? id=happyBabel'}],}, {test: /\.(sc|sas|c)ss$/,
		    use: [
		        'style-loader'// Create a style tag and add CSS to it'css-loader'// Compile CSS'postcss-loader'.'sass-loader'// SCSS]}, {test: / \. (PNG | JPG | jpeg | | GIF SVG) /, / / picture processing use: {loader:'url-loader',
				options: {
				    esModule: false// Enable the commonJS module syntax to successfully display outputPath when importing images using require:'images/'// Image output pathlimit: 10 * 1024 //url-loader will BASE64 encode the image when the image is smaller thanlimit}}}, {test: /\.(eot|woff2? | the vera.ttf | SVG) $/, / / font processing 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/'}}]}]},Copy the code

(2) Detailed explanation of webpack.dev.config.js file

  • NPM install webpack-merge -d import a package called webpack-merge and merge the contents of the above webpack.config.base.js files

  • (Optional) Import the PortFinder package to automatically select a new port when the currently set port is occupied

  • (Optional) Introduce the friendly-errors-webpack-plugin package to make webpack log error reporting more friendly

  • Important: HMR module needs to be introduced here to realize heat replacement

  • Code description:

  1. mode: 'development'Using the developer mode in webpack4
  2. entry: ['react-hot-loader/path']Heat replacement is implemented to use the HMR module in Webpack. When configuring this module, you need to set the local devServer, sethot:trueAnd create the module in plugins here for it to take effect. And create a. Babelrc file in the root directory where you set:"plugins":["react-hot-loader/babel"](.babelrc file setup will be discussed later.)
  3. devServerYou can specify the host and port used in the
const path = require('path')
const merge = require('webpack-merge')
const commonConfig = require('./webpack.config.base')
const webpack = require('webpack')
const portfinder = require('portfinder')
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin"); Const devWebpackConfig = merge(commonConfig, {'development',
	entry: [
		'react-hot-loader/patch'
	],
	devtool: 'inline-source-map'// Output directory path: path.resolve(__dirname,'./dist'), // Filename:'bundle.js',}, plugins: [/ / open HMR (hot replace feature, replaced part, without reloading the page) is equivalent to the command line, hot new webpack. HotModuleReplacementPlugin ()], devServer: {hot:true,
		contentBase: path.resolve(__dirname, './dist'),
		host: 'localhost',
		port: 8000,
		historyApiFallback: true// All 404's connect to index.html proxy:{// Proxy to the back end of the service address, will block all request addresses starting with API'/api': 'http://localhost:8000'
		},
		clientLogLevel: 'none'}}); // With portFinder, when the default port is occupied, Module.exports = new Promise((resolve, reject) => {portFinder.getPort ((err, port) => {portFinder.getPort ((err, port) => {if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary fore2e tests process.env.PORT = port // add port to devServer config devWebpackConfig.devServer.port = port // Resolve (devWebpackConfig) devWebpackConfig. Plugins. Push (new FriendlyErrorsPlugin ({/ / remove the console clearConsole original information:true, // Console notification to developers after successful packaging compilationSuccessInfo: {messages: [' Development environment started successfully, project running at: http://${devWebpackConfig.devServer.host}:${port}}, // onErrors: () => {console.log()"Failed to pack") }
      }))
      resolve(devWebpackConfig)
    }
  })
})

Copy the code

(3) Detailed explanation of webpack.prod.config.js file

  • Here is the output location of the setup file build case and the configuration to use accordingly
const path = require('path')
const webpack = require('webpack')
const merge = require('webpack-merge')
const commonConfig = require('./webpack.config.base')

module.exports = merge(commonConfig, {
	mode: 'production'// Output directory path: path.resolve(__dirname,'./dist'), // Filename:'[name].[contenthash].js',
		chunkFilename: '[name].[contenthash].js'
	},
	optimization: {
		usedExports: true,
		splitChunks: {
			chunks: 'all',
			cacheGroups: {
				vendors: {
					test: /[\\/]node_modules[\\/]/,
					name: 'vendors'
				}
			}
		}
	},
	plugins: [
	]
})

Copy the code
  1. Create files in the root directorypostcss.config.jsPostcss cannot be parsed after the code project upload git and pull it
module.exports = {
  plugins: {
    'postcss-cssnext': {}}}Copy the code
  1. Create it in the root directory.babelrcFile used to configure the required babel-loader information:
// Install the following libraries: @babel/preset-env, @babel/preset-react, @babel/plugin-proposal-class-properties, and react-hot-loader/ Babel NPM install @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties react-hot-loader/babel -D npm install babel-plugin-importCopy the code
{
  "presets": [
    "@babel/preset-env"."@babel/preset-react"]."plugins": [
    "react-hot-loader/babel"// The HMR hotreplace plug-in needs to be installed separately. After configuring the.babelrc file, it can be called in the entry file index.js to set up and determine the time of hot replace"@babel/plugin-proposal-class-properties"In this way, antD styles can be introduced globally, without the need to import styles at the top of the entry file. In this way, antD styles can be imported globally.  // If you do not use ANTD's component library, you do not need to configure the following section ["import", {
      "libraryName": "antd"."libraryDirectory": "es"."style": "css" // `style: true'less file will load}]]}Copy the code

For the introduction of ANTD, you can refer to the following two documents:

  • Official document: github.com/ant-design/…
  • Jane: www.jianshu.com/p/bb6bf5647…
  1. Create entry fileindex.js, inside the SRC folder, as the entire WebPack configuration, you need to tell WebPack where to start packing the files.
  • First, as you can see in step 2 above, we confirmed the location of the entry file when configuring the basic generic Settings for WebPack:entry: ["./src/index.js"]
  • Then, inside the file, we create a basic content, mainly to connect to our routing file, so that when we start the service, we can access different pages through different routes. But at the same time, according to the previous Settings, we can configure the content of HMR, so that our service can monitor whether there is hot update, so as to refresh the page or module:
// src/index.js
import 'babel-polyfill'// babel-polyfill import React from'react'// Introduce the react module import ReactDOM from'react-dom'// Import Routes from the ReactDOM module'./router'// reactdom.render (<Routes/>, document.getelementbyid ('root') // Easy use of heat replacement: If module.hot is detected, update the hot moduleif (module.hot) { 
	module.hot.accept()
}

Copy the code

At the same time, create an index.html file in the SRC folder as the HTML file pointed to by index.js

// src/index.html <! DOCTYPE html> <head> <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.4.1/css/swiper.min.css"< span style = "max-width: 100%; clear: both; min-height: 1emtype="text/css">
      .icon {
        fill: currentColor;
        overflow: hidden;
      }
    </style>
</head>

<body style='min-height: 100vh'>
  <div id="root" style='min-height: 100vh'></div>
</body>

</html>

Copy the code
  1. You can configure ESLint by referring to Airbnb’s ESLint Settings or depending on your own needs

    References:

  • Github.com/lin-123/jav…
  • Juejin. Cn/post / 684490…
  1. routerSettings:
// src/router/index.js
import React from 'react'
import { Route, Redirect, Switch, HashRouter as Router } from 'react-router-dom'
import Main from 'pages/Main'Log (module.hot) const Routes = () => (<Router> <Switch> <Route exact path="/" render={() => (
				<Redirect to="/main"/>
			)}/>
			<Route path='/main' component={Main}/>
		</Switch>
	</Router>
)

export default Routes

Copy the code
  1. Write a normal page page –main
import React from 'react'
import './index.scss'
import SampleAction from 'actions/sample'
import { Button } from 'antd'// Import the antD component Common from'components/common'// Introduce common componentsexport default class Main extends React.Component {

	constructor (props) {
		super(props)
		this.state = {
      
		}
	}

	componentDidMount () {
		this.requestInfo()
	}

	requestInfo = async () => {
		console.log(SampleAction)
		let res = await SampleAction.getAlgorithmsInfo({ code:'simple2complex' })
		console.log(res)
	}

	render () {
		return (
			<div className='main'>
				<Common/>
				<Button type='primary'>TEST</Button>
				<button>normal button</button>
			</div>
		)
	}
}

Copy the code
  1. The page for the common component:
import React from 'react'
import './index.scss'

export default class Common extends React.Component {
	constructor (props) {
		super(props)
		this.state = {

		}
	}

	render () {
		return (
			<div>
                COMMON COMPONENTS
			</div>
		)
	}
}

Copy the code
  1. Final configuration highlights:package.json— Sets the scripts to run
// Add the following paragraph to package.json to configure the sciPTS we need to use when running or packaging the project"scripts": {
    "dev": "webpack-dev-server --config ./webpack.dev.config.js --color --progress --open"."start": "npm install && webpack-dev-server --config ./webpack.dev.config.js --color --progress --mode development --open"."build": "webpack --config ./webpack.prod.config.js --color --progress"
  },
Copy the code

4. Run the project

  • Launch project:yarn start
  • Debugging project:yarn dev
  • Package items:yarn build
  • Install dependencies:yarnnpm install <--package name--->

5. Running result

  • Open thehttp://localhost:8000/#/main
  • Chrome page: