手动搭建react项目框架

851 阅读4分钟

1、基础环境

  1. 初始化一个pacage.json文件
npm init -y

2.安装webpack及webpack-cli

npm i webpack webpack-cli -D

3.新建webpack.config.js来配置文件

webpack.config.js

4.webpack.config.js的基础设置

module.exports={
  entry:{},     //入口配置*
  output:{},    //出口配置*
  modules:{},   //module.rules loader
  plugins:[],   //插件配置
  devServer:{}   //服务器配置(开发环境, 生产环境)
}

5.新建src文件

mkdir src

在src文件下新建index.html和main.js

cd src
index.html main.js

在index.html写入如下代码

<!DOCTYPE html>
<html lang="zh-CN">
  <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" />
    <link rel="icon" href="nowthen.jpg" />
    <title>林深配置react项目</title>
  </head>
  <body>
    <noscript>
      <strong>
        林深配置react项目
      </strong>
    </noscript>
    <div id="app"></div>
  </body>
</html>

这时候需要下载react react-dom react-router antd

npm i react react-dom react-router antd --save

然后再main.js中写入如下代码

import React from 'react';
import ReactDom from 'react-dom';
import { ConfigProvider } from 'antd';
import zhCN from 'antd/es/locale/zh_CN';

const App = () => (
  <ConfigProvider locale={zhCN}>
    <div>临时</div>
  </ConfigProvider>
);

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

6.新建build文件(区分开发环境和生产环境)

mkdir build

新建webpack.dev.js、webpack.prod.js和一个公共的webpack.common.js。

接下来安装HTML模板

npm i html-webpack-plugin -D

在webpack.commom.js中配置


const srcPath = path.join(__dirname, "../src");

module.exports = {
  entry: {}, //入口配置
  output: {}, //出口配置
  module: {}, //module.rules loader
  plugins: [
    new HtmlWebpackPlugin({
      template: `${srcPath}/index.html`
    })
  ], //插件配置
  devServer: {}, //服务器配置(开发环境, 生产环境)
}

配置本地服务和热更新

npm i webpack-dev-server clean-webpack-plugin -D

本地服务在webpack.dev.js中配置 安装webpack-merge copy-webpack-plugin 说明:合并配置文件的工具 npm i webpack-merge copy-webpack-plugin -D

const webpack = require('webpack');
const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
module.exports = merge(commonConfig, {
  mode: 'development',
  // 开发环境本地启动的服务配置
  devServer: {
    port: 3000,
    hot: true,
    open: true,
    historyApiFallback: true,
    compress: true,
    proxy: {
      '/testapi': {
        target: 'xxxx',//代理地址
        changeOrigin: true,
        secure: false,
        pathRewrite: { '^/testapi': '' },
      },
    },
  },
  plugins: [new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin()]
});

在main.js中添加

// 热更新
if (module.hot) {
  module.hot.accept(err => {
    if (err) {
      console.error('module.hot,', err);
    }
  });
}

7.安装babel

npm i babel-loader @babel/core @babel/plugin-transform-runtime 
	@babel/preset-env @babel/preset-react  
	babel-plugin-import @babel/plugin-proposal-class-properties 

@babel/preset-react转换React jsx语法 @babel/plugin-proposal-class-properties 转换 Class语法 babel-plugin-import 配合实现React组件的按需加载 在webpack.commom.js中配置

rules: [
   {
       test: /\.(js|jsx)$/,
       include: [srcDir],
       use: ["babel-loader?cacheDirectory=true"]
   },
]

新建.babelrc文件并在里面配置

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/transform-runtime",
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    [
      "import",
      {
        "libraryName": "antd",
        "libraryDirectory": "es",
        "style": "css" // `style: true` 会加载 less 文件
      }
    ]
  ]
}

因为一直使用的是less,所以这里就配置less和图片等资源

npm i less less-loader style-loader css-loader url-loader 
	mini-css-extract-plugin postcss-loader autoprefixer -D

less-loader、style-loader、css-loader 处理加载less、css文件; postcss-loader、autoprefixer 处理css样式浏览器前缀兼容; url-loader 处理图片、字体文件等资源; mini-css-extract-plugin 分离css成单独的文件; 在webpack.prod.js中配置

const webpack = require("webpack");
const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const commonConfig = require("./webpack.common");
module: {
  rules: [
    {
      test: /\.less$/,
      use: [
        devMode ? "style-loader" : MiniCssExtractPlugin.loader,
        "css-loader",
        "postcss-loader",
        "less-loader"
      ]
    },
    {
      test: /\.css$/,
      use: [
        devMode ? "style-loader" : MiniCssExtractPlugin.loader,
        "css-loader",
        "postcss-loader"
      ]
    },
    {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      use: ["url-loader"],
      include: [srcDir]
    },
    {
      test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
      use: ["url-loader"],
      include: [srcDir]
    },
    {
      test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
      use: ["url-loader"],
      include: [srcDir]
    }
  ]
},
plugins: [
  new MiniCssExtractPlugin({
    filename: "[name].[contenthash:8].css",
    chunkFilename: "chunk/[id].[contenthash:8].css"
  }),
  ],

配置postcss .postcssrc.js文件

module.exports = {
  plugins: {
    autoprefixer: {}
  }
};

利用happypack 多线程打包

npm i happypack -D

在webpack.common.js中配置

const os = require("os");
const HappyPack = require("happypack");
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
module: {
  rules: [
    {
      test: /\.(js|jsx)$/,
      include: [srcDir],
      exclude: /(node_modules|bower_components)/,
      use: ["happypack/loader?id=happybabel"]
    },
  ]
},
plugins: [
  //开启 happypack 的线程池
  new HappyPack({
    id: "happybabel",
    loaders: ["babel-loader?cacheDirectory=true"],
    threadPool: happyThreadPool,
    cache: true,
    verbose: true
  }),
]

生产环境 拆分模块

optimization: {
    runtimeChunk: {
      name: "manifest"
    },
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        dll: {
          test: /[\\/]node_modules[\\/](react|react-dom|react-dom-router|babel-polyfill|mobx|mobx-react|mobx-react-dom|antd|@ant-design)/,
          minChunks: 1,
          priority: 2,
          name: "dll"
        },
        codeMirror: {
          test: /[\\/]node_modules[\\/](react-codemirror|codemirror)/,
          minChunks: 1,
          priority: 2,
          name: "codemirror"
        },
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          minChunks: 1,
          priority: 1,
          name: "vendors"
        }
      }
    }
  }

引入 ESLint 与 Prettier规范化团队项目代码开发,统一代码风格。

npm i prettier babel-eslint eslint eslint-loader eslint-config-airbnb 
eslint-config-prettier eslint-plugin-babel eslint-plugin-import 
eslint-plugin-jsx-a11y eslint-plugin-react -D

新建.eslintrc.js写入

module.exports = {
  extends: ['airbnb', 'prettier'],
  env: {
    browser: true,
    node: true,
    es6: true,
    jquery: true,
  },
  parser: 'babel-eslint',
  plugins: ['react', 'babel'],
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warning' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warning' : 'off',
    'prefer-destructuring': 0,
    'no-else-return': 0,
    'import/no-extraneous-dependencies': 0,
    'import/no-unresolved': [2, { ignore: ['^@/'] }],
    'react/jsx-props-no-spreading': 0,
    'react/jsx-one-expression-per-line': 0,
    'react/prop-types': 0,
    'react/forbid-prop-types': 0,
    'react/jsx-indent': 0,
    'react/jsx-wrap-multilines': [
      'error',
      {
        declaration: false,
        assignment: false,
      },
    ],
    'react/jsx-filename-extension': [
      1,
      {
        extensions: ['.js', '.jsx'],
      },
    ],
    'jsx-a11y/no-static-element-interactions': 0,
    'jsx-a11y/anchor-has-content': 0,
    'jsx-a11y/click-events-have-key-events': 0,
    'jsx-a11y/anchor-is-valid': 0,
    'comma-dangle': ['error', 'always-multiline'],
  },
};

然后将package.json中script配置改为

"scripts": {
    "start": "webpack-dev-server --color --inline --progress --config build/webpack.dev.js",
    "build": "NODE_ENV=production webpack --progress --config ./build/webpack.prod.js",
    "build:report": "NODE_ENV=production webpack --progress --config ./build/webpack.prod.js",
    "build:watch": "NODE_ENV=production webpack --progress --config ./build/webpack.prod.js"
  },

在webpack.prod.js中添加

if (process.env.npm_lifecycle_event == "build:watch") {
 config = merge(config, {
   devtool: "cheap-source-map"
 });
}
if (process.env.npm_lifecycle_event === "build:report") {
 const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
   .BundleAnalyzerPlugin;
 config.plugins.push(new BundleAnalyzerPlugin());
}

命令行运行

// 命令行执行
// 运行开发环境;
npm start 

// 生产环境打包压缩;
npm build

// 图形化分析打包文件大小;
npm build:report

// 方便排查生产环境打包后文件的错误信息(文件source map);
npm build:watch

作者:nowThen
链接:https://juejin.cn/post/6844904035099623437
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

通过npm start启动服务之后发现会报错Error: No PostCSS Config found in.postcss.js中配置

module.exports = {
  plugins: {
    'autoprefixer': {browsers: 'last 5 version'}
  }
};

还是会报错,后来我将wabpck.common.js中的postcss-loader删除掉之后再运行就可以了,具体原因还在研究。后续会完善更新

这个根据webpack搭建react项目是参照nowThen大佬的文章搭建的但是有些细节还是没有写出来,所以我也是添加了点细节,哈哈,不喜勿喷,我是个小前端还有很多东西在学习,大佬链接