手动搭webpack + React Hooks + TypeScript + Antd(一)

959 阅读3分钟

本文章手动搭建react工程,使用hooks + ts, antd多主题,大概分为四章

新建example文件夹然后初始化package.json文件

mkdir example
cd example
yarn init // 根据提示输入

package.json就建好了

先介绍一下npm

npm脚本一般放在scripts里面,run的时候会拉起一个shell脚本跑里面的代码,npm可以串并行

  • '&' 并行执行顺序,同时执行

    "dev":"node test.js & webpack"

  • '&&' 继发顺序,执行前面之后才可以执行后面

    "dev":"node test.js && webpack"

在scripts中写入export DEV_HOST, 在test.js中通过process.env.DEV_HOST就可以获取到'pro',

"scripts": {   
    "test": "export DEV_HOST=pro && node build/test.js"
},

根目录新建build文件夹,新建test.js文件,写入

console.log('---process.env.DEV_HOST--', process.env.DEV_HOST);

然后执行 npm run test

开始安装webpack

yarn add webpack webpack-cli -D

创建以下文件目录

build
    webpack.common.js
    webpack.prod.js
    webpack.dev.js

src
    index.js

package.json

先写点简单命令

build/webpack.dev.js

const path = require('path');
module.exports = {   
    mode: 'development',    
    devtool: 'inline-source-map',    
    entry: './src/index.js',    
    output: {          
        path: path.resolve(__dirname, "../dist"),           
        filename: "bundle.js"  
    }
};

src/index.js

console.log('hello')

package.json

"scripts": {   
    "dev": "webpack --config ./build/webpack.test.js",   
},

执行npm run dev,dist目录会生成bundle.js, node bundle.js, 会打印hello

安装配置webpack-dev-server  webpack-merge

yarn add webpack-dev-server webpack-merge -D

package.json

 "scripts": {       
    "dev": "webpack ./build/webpack.dev.js",  
  + "start": "export DEV_HOST=$(ifconfig | grep broadcast | awk '{print $2}') && webpack-dev-server --config ./build/webpack.dev.js",
 },

(ifconfig | grep broadcast | awk '{print 2}')是mac下获取当前ip地址的命令

--config用来指定配置文件,不指定则默认为根目录下的webpack.config.js,__webpack的命令

build/webpack.dev.js

devServer: {    
    contentBase: './dist',    
    host: '0.0.0.0',    
    public: `${process.env.DEV_HOST || localhost}:8080`,    
    hot: true,  
},

run起来 可以直接访问http://10.180.6.207:8080/bundle.js

安装clean-webpack-plugin html-webpack-plugin

yarn add clean-webpack-plugin html-webpack-plugin -D

clean-webpack-plugin 每次打包时清理上次打包生成的目录

html-webpack-plugin 生成打包文件中的 index.html

build/webpack.dev.js新增

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin'); 

// module.exports新加
plugins: [   
    new HtmlWebpackPlugin(),  
    new CleanWebpackPlugin(),
]

拆分webpack.common.js  webpack.dev.js  webpack.prod.js文件

webpack.prod.js和webpack.dev.js不同的是没有devServer

package.json scripts新增

"build": "webpack --config ./build/webpack.prod.js",

build/webpack.common.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const resolve = p => path.resolve(__dirname, p);

module.exports = {  
    entry: './src/index.tsx',  
    output: {    
        filename: 'bundle.js',    
        path: resolve('../dist'),   
    },  
    plugins: [    
        new CleanWebpackPlugin(),    
        new HtmlWebpackPlugin(),  
    ]
};

webpack-merge有个坑,4.x的时候直接引入可以使用

const merge = require('webpack-merge');
_但是5.x的时候这么用要报错 将webpack-merge打印_

_源码是输出的es6_

_改成解构使用即可_
const { merge } = require('webpack-merge');

最终build/webpack.dev.js

const { merge } = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {  
    mode: 'development',  
    devtool: 'inline-source-map',  
    devServer: {    
        contentBase: './dist',    
        host: '0.0.0.0',   
        public: `${process.env.DEV_HOST || localhost}:8080`,    
        hot: true,  
    },
});

build/webpack.prod.js

const { merge } = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {  
    mode: 'production',  
});
然后npm run build会在dist下生成bundle.js和index.html(可直接点开访问)index.html直接引入了bundle.js

安装 react react-dom

yarn add react react-dom

src/index.js

import React from 'react';
import ReactDOM from 'react-dom'; 
function App() {   
    return (      
        <div>start</div>   
    )
}

ReactDOM.render(<App />, document.getElementById('root'));
然后npm run start 发现报错了

因为react独有的jsx语法需要进行转义才能使用,转义需要用babel,先将jsx -> es6, 在将es6 -> es5

安装babel  babel各个模块之间的关系

yarn add @babel/core @babel/cli @babel/preset-env -D
yarn add @babel/preset-react -D
yarn add babel-loader -D

build/webpack.common.js 新增module配置

module: {  
    rules: [ 
        {     
            test: /\.(js|jsx)$/,      
            exclude: /node_modules/,      
            use: [        
                {          
                    loader: 'babel-loader',          
                    options: {            
                        presets: ['@babel/preset-react'],          
                    }        
                }      
            ],    
        },  
     ],
},
然后npm run start 打开页面报错

因为页面`document.getElementById('root')`没有这个元素,新建public文件夹,写入index.html文件,在body中添加`
`
即可,页面已经正常显示。

由于一般babel的配置都是放在babel.config.js中,所以根目录新建babel.config.js文件并写入配置,webpack的loader配置修改

build/webpack.common.js 修改module配置

{       
    test: /\.(js|jsx)$/,           
    exclude: /node_modules/,        
    use: 'babel-loader',     
},

babel.config.js

module.exports = function(api) {    
    const presets = [
        '@babel/preset-react',    
    ];    
    const plugins = [];    
    return {      
        presets,      
        plugins,   
    };
}

重新run会报错

需要加上 `api.cache(true);`
module.exports = function(api) {  
  + api.cache(true);  
    const presets = [
        '@babel/preset-react',    
    ];    
...

api.cache(true);在babel的介绍

babel7主要就是两个包,@babel/cli和@babel/core,cli用于执行命令行,core则是babel用于解析、转换、代码生成的核心包。 如果只跑babel-loader, 不在config中加入任何presets和plugins。   解释

如果只跑babel-loader, 不在config中加入任何presets和plugins

const fun = () => {
    const isarr = Array.isArray([1, 2, 3]);
    console.log('---index.js---', isarr);
};
fun()
经过转换后的bundle.js

如果presets加入
const presets = [
    ['@babel/preset-env', {
        modules: false,
    }],
];

转换后

babel默认只转语法,不转api,如果需要转换api 则需要引入babel-polyfill 

用了babel还需要polyfill吗???   babel-polyfill怎么引入

所以`Array.isArray`并没有转换

安装babel-polyfill

yarn add @babel/polyfill

直接在index.js中引入 

import "@babel/polyfill";

再build,本来10K的bundle变成了855K

直接引入babel-polyfill相当于直接引入

import "core-js/stable"; 

import "regenerator-runtime/runtime";

可以安装个 webpack-bundle-analyzer来看看webpack打包性能

yarn add -D webpack-bundle-analyzer

build/webpack.dev.js

+ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;   
...
plugins: [    
    + new BundleAnalyzerPlugin() 
]
...

然后run start可以看到打包的文件大小

所以现在可以在babel.config.js的@babel/preset-env中加入

const presets = [
    ['@babel/preset-env', {
        modules: false,
      + useBuiltIns: 'usage', // 实现按需加载    
    }],
];
实现按需加载,再run build打包体积变成了44K

webpack react已经引入了,下面就开始引入react-router loadable啦