Before, THERE was an article about how to build a Vue project with React. Now let’s talk about how to build a React project with Webpack. Personally, there are more problems in building a React project than a Vue project. The following article will explain one by one, nonsense not to say, directly open dry

React has scaffolding, why build webpack? This is not looking for trouble, to build their own technology to improve their own, understand some of the underlying technology is also very helpful, maybe later when the interview just asked it! At the beginning of the construction, there were also many pits

The first step, as usual, is to initialize the project in the folder NPM init-y

General tool installation is -d; -s is something we use from development to launch

1. Project Catalog

My project directory structure is like this. According to my personal development habit, the following examples use main.js. I personally use app.js for real development

Dist: output folder in pubilc index.html: entry HTML file Assets: store images and icon components: store encapsulated public components utils: store globally encapsulated JS file Views: related file app.js: Global JS file, configuration related

2. Create a project directory and related files

  • Create a SRC folder under the root directory to store the project files. Create a new public folder and create index.html as the entry HTML file
  • Create main.js in the root directory as the webPack entry file

3. Webpack installation

  • Install webpack:npm i webpack -D
  • Install webpack – the cli:npm i webpack-cli -D
  • Create webpack.config.js in the root directory and simply configure it

If we don’t configure webpack.config.js and enter webpack directly on the terminal, an error will be reported, as shown in the figure below

Then let’s do a simple configuration. Exports: module. Exports: module. Exports: module. Exports: module. Can we use export default? Of course not, because Webpack is developed based on Node. The second one is ES6 syntax, Node can’t recognize it, so WebPack can’t recognize it either

Note: After Webpack 4.x, in pink’s words, conventions are greater than configurations. The goal is to reduce the size of the configuration file

The dist folder also contains main.js

Here to remind you, it is not recommended to install webpack5.x version, the reason is: configuration and prone to incompatible error problems, pit too much; And now 4. X stable batch

  • Install webpack-dev-server: NPM install webpack-dev –save-dev

The current installation is the latest 5.x version, the error will be reported when the run is running, because the version is incompatible, it is ok to install the webpack version as 4.x, it is not recommended to install the 5.x version. After changing to the 4.x version, I run the script again. Wow, it is running successfully. I look carefully and see how it is different from what I expected

When I right-click the source code, I see main.js in a dist folder in the root directory. Why? Because webpack-dev-serve packaged main.js is hosted in memory, it is not visible in the root directory

The main. Js path we refer to in index. HTML is written dead, so it will always be the same file. Change the path or give it to a plugin instead of referring to it

  • Configuration automatically open the browser after running, I generally do not configure, because I am too lazy!! Just add the following to run the script just inpackage.jsonAdd the following code to the script part of the running script

–open: automatically opens the browser. After adding the corresponding browser name, you can open different browsers, for example, –open Firefox

— Port 3000: indicates the port running at 3000

–hot: implements hot overload

— Progress: indicates progress

–compress: indicates that data is compressed when traveling the network.

–host: specifies the port number. The default port number is localhost. You can change the port number by adding a space and a port number to –host 129.0.0.1

4. Install htML-webpack –plugin

Now the browser is not what we want when it runs successfully, so we need to use a plug-in: * Webpack4. X * webpack4. X * webpack4. X * webpack4. NPM I –save-dev html-webpack-plugin, which helps us generate HTML pages into memory

In the webPack configuration file, you can create a plugins node. In the new node, you can pass two parameters: template and filename

Webpack official documentation – tml-webpack-plugin:webpack.js.org/plugins/htm…

NPM official documentation – tml-webpack-plugin:www.npmjs.com/package/htm…

  • Template: depends on who generated the template, the source file
  • Filename: indicates the name of the generated target file

Run the project again to see the result. Ok, perfect

At this time, we right click to check the source code and see a reference to main.js, which is generated by the plug-in for us, so it is ok to remove the reference to index.html above, after all, sometimes I write my own writing will not avoid problems

Install react and react-dom

NPM I react react-dom-s

2. Import main.js

Let’s start by rendering a basic div

6. Install Babel

React creates components in class mode. React creates components in class mode.

He tells us that there should be a loader to handle this type, using Babel to handle this syntax, and webPack can only package js files

Here is the installation: npm install babel-loader@8 @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties @babel/preset- react-d

Configure the Babel

Add the module node to webpack.config.js and configure it, or create a new.babelrc file. I prefer the first one because you don’t need to create a new file. (Full configuration at the bottom of the article)

/ / module configuration rules module: {/ / third party matching rules (multiple loader must write array) rules: [{test: / \. Js | JSX $/, exclude: / node_modules /, use: 'babel-loader'}// Exclude from babel-loader to exclude from babel-loader]}Copy the code

Root directory to create a.babelrc file (for more people, here is also a new file configuration method)

Run again at this time to see, OK perfect

7. Configure the path and alias

As a lazy person, this is something I have to configure so that I can have less code

Add the resolve node to webpack.config.js and write the following code

Resolve: {/ / omit suffix extensions: [' * 'and' js', 'JSX', 'json'], / / configuration path alias alias: {' @ assets: path.resolve('./src/assets'), '@views': path.resolve('./src/views'), '@utils': path.resolve('./src/utils'), '@components': path.resolve('./src/components') }, }Copy the code

So now we’re going to import the file and just write it like this

React uses CSS and SCSS. CSS modular

If you write style are inline, this step can not see, should be very few people ~~~~~~~~~~~

For complete CSS configuration and modularity, please refer to the appendix at the bottom. It is very complete there. This section describes how to use and configure some CSS

The configuration of Sass is covered below

Webpack CSS processing flow:

  1. When Webpack is packaged to a file, it sees a file with a suffix named.css. At this time, Webapck cannot identify the file and will take it to the third party loader in rules

  2. When such loader is found, it will start processing from the last loader, namely CSS-loader. After csS-loader is processed, it will check whether there are other loaders in front of it. In this case, there is a style loader in front of it. At this time, I will go to the front to find if there are other loaders. If there are, I will hand them to the front for processing

  3. When the last loader has finished processing it will be handed over to WebPack for packaging and merging

Installing related Loaders

npm i style-loader css-loader -D
Copy the code

To configure the CSS – loader

CSS modular

We can also not use SASS, and directly modularize CSS. What if we use a third party UI framework, just add a exclude to rules

To use CSS modularity here, first install a plugin: mini-CSS-extract-plugin: NPM install –save-dev mini-css-extract-plugin this plugin is mainly used to convert CSS from other styles and extract CSS. Filename is the address of the CSS file we want to output

const MiniCssPlugin = new MiniCssExtractPlugin({
        filename: './css/common.css'
})
Copy the code

Import in the plugins node of the webpack.config.js file

plugins: [
        HtmlPlugin, MiniCssPlugin
],
Copy the code

To use it, see the image below. Set module to True to enable modularity

** Note: this plugin does not work with style-loader, sass and less files, and is mainly used for CSS files. It's better to come first **Copy the code

rules: [ { test: /\.js|jsx$/, exclude: /node_modules/, use: {test: /\. CSS $/, exclude: /node_modules/, use: [MiniCssExtractPlugin.loader, {loader: 'css-loader', options: { modules: true, importLoaders: 1}}}], / / packaged font and image file loader {test: / \. The vera.ttf | woff | woff2 | eot | SVG | PNG | JPG | GIF $/, use: 'url - loader'},]Copy the code

9. Install url-loader and file-loader

Installing these two loaders will help us to process font files and image files

Installation: NPM I url-loader file-loader -d

Configure it in the moudle——>rules node

/ / with packaging fonts, image file loader {test: / \. The vera.ttf | woff | woff2 | eot | SVG | PNG | JPG | GIF $/, use: 'url - loader'}Copy the code

10. Install and configure SASS

Sass-loader internally relies on Node-sass. You are advised to use the node-sass installation command on the NPM official website: NPM install node-sass. Sass -loader: NPM install sass-loader sass webpack –save-dev NPM run start, this time found terminal error (here select less error, SCSS error picture can not be found, but all the same

The error message tells us that getOptions is not a method. The reason for this is that the version of Sass-Loader is too high, change the version number, and it is recommended to install the version below 8.x, as well as Node-sass. Because the latest version is installed by default, a 5.x was installed by default at the beginning. The terminal also reported an error and said it was best to install 4.x

I did not modularize CSS in the following configuration, because when the project uses THE UI framework in the future, all the CSS files will be introduced. In order to avoid any problems in the future, I’d better use Sass, our own files are.SCSS ending, The UI framework is. CSS below postCSS-loader to webpack official look at the document, the document is very detailed, here will not say

Webpack document: webpack.js.org/loaders/pos…

NPM document: www.npmjs.com/package/pos…

rules: [ { test: /\.scss$/, use: ['style-loader', { loader: 'css-loader', options: { modules: true, importLoaders: 1, } }, 'sass-loader'] }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: {importLoaders: 1,}}, {loader: 'postCSs-loader ', options: {// Configure options and plug-ins postcssOptions: {importLoaders: 1,}}, {loader:' postCSs-loader ', options: {// Configure options and plug-ins postcssOptions: {plugins: [ autoprefixer(["last 2 version", "> 1%", "not ie < 11"]), pxtorem({ rootValue: 16, unitPrecision: 5, propList: ["font", "font-size", "line-height", "letter-spacing", "width", "height", "margin", "padding"], selectorBlackList: [], replace: true, mediaQuery: false, minPixelValue: 0, exclude: /node_modules/i }) ] } } } ] } ]Copy the code

10. Package test

Now that everything we need is configured, make a package and try it out. Go

There is already a dist folder in my project, although I do not know what it is, it is ok, I will change the last package file to another one

Write the packaging command in package.json

"build": "webpack --progress --config webpack.config.js"
Copy the code

Fly for me !!!!! ~ ~ ~ ~ ~ ~

In general, our packaged files are dist folder, you can take a look at the directory at the end of this article, there is a very complete configuration, I have changed outPutDist to dist folder, packaging is the same, there are some packed HTML, JS, CSS files

The static folder contains our CSS and some image files. We use the mini-CSs-extract-plugin to combine CSS into one

At this point, the packaging is complete

11, Appendix (must see!!)

  1. Sometimes there are too many dependencies to install one by one, so put all the dependencies and part of the WebPack configuration here. Then directly copy the past, and then directly NPM install can be convenient for everyone to use
  2. There is a TS-related loader installed inside. If you do not need to install TS, you can use JS directly
  3. @babel/plugin-proposal-class-properties” and @babel/plugin-transform-runtime do not need to be installed
  4. When configuring Babel, I did not use the create. Babelrc file to configure it. It is too troublesome to configure Babel directly in the Webpack configuration file

Package. json complete code

{" name ":" the react - cli ", "version" : "1.0.0", "description" : ""," main ":" index. Js ", "scripts" : {" test ", "echo \" Error: no test specified\" && exit 1", "build": "webpack --colors --progress --profile", "start": < span style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; white-space: inherit! Important;" "^ 7.12.13 @", "Babel/plugin - transform - runtime" : "^ 7.12.15", "@ Babel/preset - env" : "^ 7.12.13", "@ Babel/preset - react" : "^ 7.12.13 @", "Babel/runtime" : "^ 7.12.13", "autoprefixer" : "^ 10.0.2", "Babel - loader" : "^ 8.2.2", "terser - webpack - plugin" : "^ 2.2.1," "the clean - webpack - plugin" : "^ 3.0.0", "CSS - loader" : "^ 5.0.1", "file - loader" : "^ 6.2.0", "HTML - webpack - plugin" : "^ 4.5.0", "mini - CSS - extract - the plugin" : "^ 1.3.1", "node - sass" : "^ 4.14.1", "postcss" : "^ 8.1.9", "postcss - loader" : "^ 4.1.0 postcss - pxtorem", "" :" ^ 5.1.1 ", "sass" : "^ 1.32.8", "ts - loader" : "^ 8.0.12", "typescript" : "^ 4.1.3 sass -", "loader" : "^ 7.3.1", "style - loader" : "^ 2.0.0", "url - loader" : "^ 4.4.1", "webpack" : "^ 4.46.0 webpack -", "cli" : "^ 3.2.1", "webpack - dev - server" : "^ 3.1.14"}, "dependencies" : {" antd ":" ^ 4.12.3 ", "axios" : "^ 0.21.0 core -", "js" : "^ 3.7.0", "qs" : "^ 6.9.4", "react" : "^ 17.0.1", "the react - dom" : "^ 17.0.1", "the react - the router - dom" : "^ 5.2.0}", "keywords" : [], "author" : ""," license ":" ISC "}Copy the code

Webpack.config.js complete code

Clean-webpack-plugin: This is used to empty dist files

Postcss – pxtorem: px is automatically turn to rem a plug-in, recommendation and postcss – loader used together

Autoprefixer: a plug-in that automatically manages browser prefixes

Terser-webpack-plugin: Package automatically remove console.log, package optimization

const path = require('path') const HtmlWebpackPlugin = require("html-webpack-plugin") const autoprefixer = require("autoprefixer") const MiniCssExtractPlugin = require("mini-css-extract-plugin") const { CleanWebpackPlugin} = require("clean-webpack-plugin") const pxtorem = require("postcss-pxtorem") const TerserPlugin = require('terser-webpack-plugin') module.exports = { mode: 'production', entry: path.join(__dirname, './app.js'), output: { path: path.join(__dirname, 'dist'), filename: "Static/js/bundle. Js",}, / / loader configuration related module: {rules: [{/ / js file, Babel configuration test: / \. Js | JSX $/, exclude: [ path.resolve(__dirname, 'node_modules') ], use: [{ loader: 'babel-loader', options: { babelrc: false, presets: [ require.resolve('@babel/preset-react'), [require.resolve('@babel/preset-env'), { "useBuiltIns": "usage", "corejs": 3, modules: false}]], cacheDirectory: true}}]}, // CSS, SCSS and modularity related configurations {test: /\. SCSS $/, use: ['style-loader', { loader: 'css-loader', options: { modules: true, importLoaders: 1, } }, 'sass-loader'] }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: { importLoaders: 1 } }, { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ autoprefixer(["last 2 version", "> 1%", "not ie < 11"]), pxtorem({ rootValue: 16, unitPrecision: 5, propList: ["font", "font-size", "line-height", "letter-spacing", "width", "height", "margin", "padding"], selectorBlackList: [], replace: true, mediaQuery: false, minPixelValue: 0, exclude: /node_modules/ I})]}}}]}, // File configuration {test: /\.(png|svg|jpg|gif|ttf|woff|woff2|eot)$/, use: { loader: "url-loader", options: { esModule: false, name: Static /images/[hash:8].[name].[ext]", limit: 3 * 1024}}}]}, // Path alias configuration resolve: {extensions: ['.json', '.ts', '.tsx','.js', '.jsx'], alias: { "@images": path.resolve("./src/assets"), "@css": path.resolve("./src/css"), "@views": path.resolve("./src/views"), "@components": Path.resolve ("./ SRC /components"), "@utils": path.resolve("./ SRC /utils")}}, [ new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: "static/css/[name].css", chunkFilename: "static/css/[id].css" }), new HtmlWebpackPlugin({ template: "./public/index.html", filename: // Minimizer: [new TerserPlugin({cache: true, sourceMap:)})], // Minimizer: [new TerserPlugin({cache: true, sourceMap: true, terserOptions: { comments: false, compress: { unused: true, drop_console: true, drop_debugger: true, dead_code: // devServer: {// host: "192.168.15.28", // port: "3001", / / historyApiFallback: true, / / proxy: {/ / agent / / 'HTTP: / / http://106.53.151.120:8888/user-info/ / /'/user - info ': {/ / target: 'http://132.232.223.165:8888/', / / changeOrigin: true, / / secure: false, / / pathRewrite: {' ^ / user - the info: } //} //} //Copy the code

App.js (aka main.js) code

So this code can be pretty neat or you can write antD components directly, so INSTEAD of creating a new file and importing it, I’ll just write it in here

import React from 'react' import ReactDOM from 'react-dom' import { HashRouter, Route, Link } from 'react-router-dom' import { Layout, Menu} from 'antd' // Import component import Home from './ SRC /views/Home' import About from './ SRC /views/About' import 'antd/dist/antd.css' const { Header, Content, Footer } = Layout ReactDOM.render( <HashRouter> <Layout style={{width:'100vw',height:'100%',flex:1}}> <Header className="header" style={{display:'flex',alignItems:'center'}}> <Menu style={{flex:1}} theme="dark" mode="horizontal"> < menu. Item key="About"> <Link to="/About"> About </Link> </Menu.Item> </Menu> </Header> <Layout> <Layout style={{ padding: '0 24px 24px' }}> <Content className="site-layout-background" style={{ margin: 0, minHeight: In 280, }}> <Route path="/Home" component={Home}></Route> <Route path="/About" component={About}></Route> </Content> <Footer style={{ textAlign: 'Center'}}>webpack -- react-cli</Footer> </Layout> </Layout> </Layout> </Layout> </HashRouter>, document.getelementById ('app'))Copy the code