react快速开始二 本地配置

前言   

很早之前写了个codepen的react教程,方案很简单,引入react、react-dom依赖,其他主要是要熟悉codepen的使用。 这个方案对于想快速上手了解react的有一定用处,但是在实际项目中还是需要本地配置一套基于react的项目结构。

目前脚手架存在的问题

 一般的框架都会有对应的cli,比如vue-cli, angualr-cli, create-react-app,最近发现react、vue的cli都将细节配置给隐藏掉了(主要是webpack配置),只能通过config变量自定义webpack配置,各种框架的方式还不太一样,react需要单独引入新的库去修改,好处是屏蔽了细节配置,将最复杂的webpack配置隐藏掉,用户开箱即用,坏处是对于初学者来说屏蔽了最复杂的配置项, 进阶的路上容易忽略掉重点。

 最近有个小需求,也开始从0搭建了一个react项目, 异常的艰难,太久没有关注这些玩意了,网上可能相关的资料已经很多了,算是记录一下自己的历程吧。

正文

准备工作

 一台电脑, 本地安装node、npm, vscode, chrome浏览器

涉及到的技术

react、webpack、babel、antd、less、postcss

步骤
  1. 首先npm init 生成package.json,生成相应的依赖
  2. 这里要关注一下devDep和dep的区别,devDependencies是基于本地环境的,代码不会打包到线上代码
  3. 创建webpack.config.js, 关注的主要几个点:
  4. entry: 入口文件
  5. output: 编译后的输入文件
  6. modules: ruels
  7. babel-loader 处理react、es678* 转成es5
  8. url-loader, file-loader 处理图片, 默认转成base64,超出将图片copy
  9. less-loader, css-loader, postcss-loader, 这里强调一下postcss, 主要是autoprefix功能, 自动区全不同浏览器的差异, 使用方式,可以在这里增加options,也可以单独创建postcss.config.js, 同事autoprefix的具体配置,最近的定义需要配置在package.json里面.
  10. devtool: 'source-map' 设置sourcemap
  11. resolve
  12. extensions,默认处理的后缀
  13. alias,自定义一些目录引用,避免在层级比较深的时候使用相对路径
  14. dev-server: 基于express 本地启动服务
// package.json
"scripts": {
  "build": "webpack --config webpack.config.js",
  "start": "webpack-dev-server --config webpack.dev.config.js"
},
"browserslist": [
  "last 5 versions",
  "> 1%",
  "not ie <= 8"
],


  1. 创建代码, 注意: 我这个例子只是为了写几个公共组件,没有引入react-router,mobx或者redux方案
  2. index.html: 主要是id,在webpack配置中使用HtmlWebpackPlugin 将js和html关联
  3. index.js, react-dom引用
  4. 创建app.js, antd引用,具体组件引用
  5. 具体react代码书写
  6. 如果需要引用移动端适配, 目前使用的是淘宝的flexible方案, 除了在js中引入'amfe-flexible', 需要在postcss配置 pxtorem, require('postcss-pxtorem')
  7. 目录结构src/
  8. assets/*, 存放图片、字体等静态资源
  9. pages/* 具体页面代码
  10. components/* 公共组件
  11. App.js 主引用代码
<!-- index.html -->
<html>
  <head>
    <meta charset="utf-8">
    <title>公共模块</title>
    <meta name="viewport" content="initial-scale=1.0, width=device-width" />
  </head>
  <body>
    <div id="root" />
  </body>
</html>


// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.less';
import App from './App';
import * as serviceWorker from './serviceWorker';

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


// app.js
import React from 'react';
import { ConfigProvider  } from 'antd';
import HeaderComponent from './components/header';
import zhCN from 'antd/es/locale/zh_CN';
import './App.less';

const App = () => (
<ConfigProvider locale={zhCN}>
  <HeaderComponent />
  </ConfigProvider>
);

export default App;


webpack如下: (目前只是一个可执行的方案,很多优化还没往里面加)

// webpack.congig.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
const path = require('path');

module.exports = {
    mode: 'development', // 'production' | 'development' | 'none'
    entry: path.resolve(__dirname, 'src/index.js'),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/env', '@babel/react'],
                        plugins: [
                            "@babel/plugin-proposal-class-properties"
                        ]
                    }
                }
            },
            // {
            //     test: /\.(png|jpg|gif)$/i,
            //     use: [
            //         {
            //             loader: 'url-loader',
            //             options: {
            //                 limit: 8192
            //             },
            //         },
            //     ],
            // },
            {
                test: /\.(png|jpe?g|gif)$/i,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[sha512:hash:base64:7].[ext]',
                        },
                    },
                ],
            },
            {
                test: /\.less$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath: '../',
                            hmr: process.env.NODE_ENV === 'development',
                        },
                    },
                    {
                        loader: 'css-loader'
                    }, {
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            plugins: [
                                require('autoprefixer')()
                            ]
                        }
                    }, {
                        loader: 'less-loader'
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.ProgressPlugin(),
        new HtmlWebpackPlugin({ template: './index.html' }),
        new MiniCssExtractPlugin({
            filename: "css/[name].css",////都提到build目录下的css目录中
            chunkFilename: "[id].css"
        })
    ],
    devtool: 'source-map',
    resolve: {
        extensions: ['.js', '.json', '.jsx', '.css'],
        alias: {
            '@': path.resolve(__dirname, 'src')
        }
    },
    devServer: {
        proxy: { // proxy URLs to backend development server
            '/api': 'http://localhost:3000'
        },
        contentBase: path.join(__dirname, ''), // boolean | string | array, static file location
        compress: true, // enable gzip compression
        historyApiFallback: true, // true for index.html upon 404, object for multiple paths
        hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
        https: false, // true for self-signed, object for cert authority
        noInfo: false, // only errors & warns on hot reload
        port: 8080
        // ...
    },
}

package.json

{
  "name": "react-demo",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "amfe-flexible": "^2.2.1",
    "antd": "^3.23.1",
    "babel-plugin-import": "^1.12.1",
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-scripts": "^2.1.8"
  },
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "start": "webpack-dev-server --config webpack.dev.config.js"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "devDependencies": {
    "@babel/core": "^7.6.2",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/preset-env": "^7.6.2",
    "autoprefixer": "^9.6.1",
    "babel-loader": "^8.0.6",
    "babel-preset-react": "^6.24.1",
    "clean-webpack-plugin": "^3.0.0",
    "css-loader": "^3.2.0",
    "file-loader": "^4.2.0",
    "html-webpack-plugin": "^3.2.0",
    "less": "^3.10.3",
    "less-loader": "^5.0.0",
    "mini-css-extract-plugin": "^0.8.0",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "postcss-loader": "^3.0.0",
    "postcss-pxtorem": "^4.0.1",
    "style-loader": "^1.0.0",
    "sugarss": "^2.0.0",
    "terser-webpack-plugin": "^2.1.2",
    "url-loader": "^2.1.0",
    "webpack": "^4.41.0",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.1"
  }
}

如果要完整的掌握react,仅仅了解它本身是不够的,还需要了解webpack、babel、redux等。

就酱!!!

暂无评论