小白学习搭建React基础架构

618 阅读3分钟

本文档是基于webpack5、node10进行搭建的,确保你的电脑里已经安装了node开发环境

1、初始化react项目

在桌面新建react-demo,同时运行npm init -y,这时可以看到项目的根目录下有package.json这个文件,这个文件类似于maven的pom.xml,用来管理前端项目中的所有依赖及其它基本信息。

2、安装webpack、webpack-cli、webpack-dev-server

npm i webpack webpack-cli webpack-dev-server -D

这三个依赖是项目基于webpack开发、打包的必要依赖。安装完之后,在根目录下新建build目录,这里我是沿用了vue-cli2的目录结构。同时在build目录下新建webpack.base.config.js文件。webpack.base.config.js的内容如下:

const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.export = (env) => {
    return {
        entry: {
            "app": path.resolve(__dirname, "../src/index.js");
        },
        output: {
            path: path.resolve(__dirname, '../dist')
        },
        module: {
            rules: [{
                test: /\.(j|t)s$/,
                use: [
                    {
                        loader: "babel-loader"
                    }
                ]
            }, {
                test: /\.(sc|c)ss$/,
                use: [
                    "loader": "style-loader",
                    "loader": "css-loader",
                    "loader": "postcss-loader",
                    "loader": "scss-loader"
                ]
            }]
        },
        plugins: [
            new HtmlWebPackPlugin({
                template: path.resolve(__dirname, "../index.html"),
                filename: path.resolve(__dirname, "../dist/index.html")
            })
        ]
    }
}

在根目录下新建index.html,内容如下:

<!DOCTYPE html>
<html>
<head>
    <title>index</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
</head>
<body>
    <div id="root"></div>
</body>
</html>

在webpack.base.config.js文件中,我们看到入口文件为src目录下的index.js文件,所以在根目录下新建src目录,在src目录下新建index.js文件,文件内容如下:

import App from './App';
import ReactDom from 'react-dom';
import React from 'react';

ReactDom.render(
  <App />document.getElementById('root'));

在根目录下新建App.js,它是页面。内容如下:

import React from 'react';

class App extends React.Component {
    render() {
        return (<div>APP 页面</div>)
    }
}

写完上述项目基本内容之后,发现好多关键依赖没装,项目此时还跑不起来。

3、安装react、react-dom

npm i react react-dom -S

react官方文档

react-dom官方文档

4、安装html-webpack-plugin、@babel/core、babel-loader、@babel/preset-env、@babel/preset-react、style-loader、css-loader、autoprefixer、node-sass、sass-loader、postcss-normalize、postcss-loader

这些插件我不一一介绍,不知道的可以百度。postcss需要配置,在根目录下新建postcss.config.js,内容如下:

const postcssNormalize = require('postcss-normalize');

module.exports = {
  plugins: [
    [
      "postcss-preset-env",
      {
        autoprefixer: {
          flexbox: "no-2009",
        },
        stage: 3,
      }
    ],
    postcssNormalize(),
    require('autoprefixer') ({
      overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
    })
  ],
};

在根目录下新建babel.config.js,内容如下:

{
    "presets": ["@babel/preset-env", "@babel/preset-react"]
}

在package.json中添加运行脚本:

"dev": "webpack serve --progress --config ./build/webpack.base.config.js",
"build": "webpack --progress --config ./build/webpack.base.config.js"

接下来可以运行项目了

5、配置文件分离

实际开发中不希望生产环境配置和开发环境配置混在一起,所以要做环境分离。安装插件webpack-merge,同时在build目录下新建webpack.dev.config.js、webpack.prod.config.js,内容分别如下:

const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.base.config");

module.exports = (env) => {
    return merge(baseConfig, {
        mode: "development",
        output: {
            filename: "js/index.bundle[hash*7].js"
        },
        devServer: {
            host: '0.0.0.0',
            port: 8080,
            hot: true
        },
        optimization: {
            moduleIds: "deterministic",
        },
        cache: {
            type: 'filesystem',
            // 可选配置
            buildDependencies: {
                config: [__filename], // 当构建依赖的config文件(通过 require 依赖)内容发生变化时,缓存失效
            },
            name: 'development-cache',
        }
    })
}
const path = require("path");
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base.config.js');
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = env => {
  return merge(baseConfig, {
    mode: 'production',
    output: {
      filename: "js/[name].bundle[contenthash][hash*7].js"
    },
    plugins: [
      // 打包之前清空打包目录
      new CleanWebpackPlugin(),
      // 打包分析
      new BundleAnalyzerPlugin(),
      // 生成 manifest.json
      new WebpackManifestPlugin(),
      // 将 css 从 js 中分离
      new MiniCssExtractPlugin({
        filename: "css/[name].[contenthash][hash*7].css",
      }),
    ],
    optimization: {
      minimize: true,
      minimizer: [
        new TerserPlugin({
          parallel: true,
        }),
        new CssMinimizerPlugin(),
      ],
      splitChunks: {
        chunks: 'async'
      },
    },
  });
}

修改webpack.base.config.js:

const path = require("path");
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
    entry: path.resolve(__dirname, '../src/index.js'),
    output: {
        path: path.resolve(__dirname, '../dist')
    },
    resolve: {
        extensions: [".js"],
    },
    module: {
        rules: [
            {
                test: /\.js?$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            },
            {
                test: /\.(c|sc)ss?$/,
                exclude: /node_modules/,
                use: {
                    loader: "style-loader",
                    loader: "css-loader",
                    loader: "postcss-loader",
                    loader: "sass-loader"
                }
            },
            {
                test: /\.(jpe?g|png|gif|svg|woff|woff2|eot|ttf|otf)$/i,
                type: "asset/resource",
            },
        ]
    },
    plugins: [
        new HtmlWebPackPlugin({
            template: path.resolve(__dirname, "../index.html"),
            filename: path.resolve(__dirname, "../dist/index.html")
        })
    ]
}

写在最后

附上项目的最终结构:

.react-demo
│  .babelrc
│  dir.md
│  index.html
│  package-lock.json
│  package.json
│  postcss.config.js
│  
├─build
│      webpack.base.config.js
│      webpack.dev.config.js
│      webpack.prod.config.js
│        
└─src
    │  App.js
    │  index.js
    │  
    └─redux
        │  index.js
        │  
        ├─actions
        │      index.js
        │      
        ├─reducers
        │      index.js
        │      
        └─sagas
                index.js