二、代码分片

默认情况下,npm run build时,create-react-app内部使用webpack将src路径下的所有代码打包成一个js文件一个css文件。对于一个大型应用,如果还把代码打包到一个文件中,会延长网页的加载时间,给用户带了不好的体验。

理想情况下,用户访问一个页面时,该页面应该只加载自己使用到的代码。解决这个问题的方案是代码分片,将js代码分片打包到多个文件,然后在访问时按需加载

create-react-app通过动态import()方法实现代码分片。import()接收一个模块的路径作为参数,然后返回一个Promise对象,Promise对象的值就是待导入的模块对象:

class App extends Component {
  handleClick = () => {
    import('./moduleA').then(({moduleA}) => {//使用moduleA
    }).catch(err => {
      //处理错误
    })
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>加载moduleA</button>
      </div>
    );
  }
}

以上会将moduleA.js和它所依赖的其他模块单独打包到一个chunk文件中,只有当用户点击了加载按钮,才开始加载这个chunk文件。

 

当项目中使用React Router,一般根据路由信息进行代码分片,每个路由依赖的代码单独打包成一个chunk。例如:

import React, { Component } from "react";

export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    constructor(props) {
      super(props);
      this.state = {
        component: null
      };
    }

    componentDidMount() {
      importComponent().then((mod) => {this.setState({
          // 同时兼容ES6和CommonJS的模块
          component: mod.default ? mod.default : mod
        });
      });
    }

    render() {
      const C = this.state.component;
      return C ? <C {...this.props} /> : null;
    }
  }

  return AsyncComponent;
}
 
asyncComponent接收一个函数参数importComponent,importComponent内通过import()语法动态导入模块。在AsyncComponent被挂载后,importComponent就会被调用,进而触发动态导入。
 
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import asyncComponent from "./AsyncComponent";

const AsyncHome = asyncComponent(() => import("./components/Home"));
const AsyncLogin = asyncComponent(() => import("./components/Login"));

class App extends Component {
  render() {
    return (
      <Router>
        <Switch>
          <Route exact path="/" component={AsyncHome} />
          <Route path="/login" component={AsyncLogin} />
          <Route path="/posts" component={AsyncHome} />
        </Switch>
      </Router>
    );
  }
}

export default App;

注意!在使用import()时,必须显式的声明要导入的组件路径,webpack在打包时,会根据这些显式的声明拆分代码,否则,webpack无法获得足够的关于拆分代码的信息。

打包后没有单独的css文件了,因为css被打包到各个chunk中,当chunk被加载执行时,会动态的把css插入页面。如果希望把chunk中的css打包到单独的文件,就需要修改webpack使用ExtractTextPlugin插件的配置,但create-react-app没有把webpack的配置文件暴露给用户,为了修改相应配置,需要将create-react-app管理的配置文件放出来。在根路径下执行:npm run eject,项目中会出现config和scripts,scripts中包含项目启动、编译和测试的脚本,config中包含项目使用的配置文件

在webpack.config.prod.js中找到配置 ExtractTextPlugin 的地方:

new ExtractTextPlugin({
  filename: cssFilename,
  allChunks: true //新加配置项
})

重新编译,各个chunk文件使用的css样式又会被统一打包到main.css

注意npm run eject不可逆

posted on 2022-11-03 10:15  Zoie_ting  阅读(97)  评论(0编辑  收藏  举报