zoukankan      html  css  js  c++  java
  • xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

    如何实现 React 模块动态导入

    React 模块动态导入

    代码分割

    webpack & code splitting

    https://reactjs.org/docs/code-splitting.html

    https://zh-hans.reactjs.org/docs/code-splitting.html

    Code-Splitting 可以创建多个可在运行时动态加载的包

    https://webpack.js.org/guides/code-splitting/

    https://rollupjs.org/guide/en/#code-splitting

    https://github.com/browserify/factor-bundle

    虽然您并未减少应用程序中的全部代码量,但避免了加载用户可能永远不需要的代码,并减少了初始加载过程中所需的代码量。

    
    
    

    https://create-react-app.dev/docs/code-splitting/

    
    
    

    https://nextjs.org/docs/advanced-features/dynamic-import

    React.lazy and Suspense are not yet available for server-side rendering.

    code-splitting & server-side rendering

    https://github.com/gregberge/loadable-components

    https://loadable-components.com/docs/server-side-rendering/

    React.lazy

    React.lazy 函数让你可以可以像导入将常规组件一样的渲染一个动态导入。

    import OtherComponent from './OtherComponent';
    
    
    // React.lazy
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    
    

    首次呈现此组件时,它将自动加载包含OtherComponent的捆绑包。

    React.lazy 采用了必须调用动态 import()的函数。
    这必须返回一个 Promise,该 Promise 解析为一个带有默认导出的模块,该模块包含一个 React组件。

    然后,应该将懒惰的组件呈现在Suspense组件中,这使我们可以在等待懒惰的组件加载时显示一些后备内容(例如加载指示符)。

    import React, { Suspense } from 'react';
    
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    
    function MyComponent() {
      return (
        <div>
          <Suspense fallback={<div>Loading...</div>}>
            <OtherComponent />
          </Suspense>
        </div>
      );
    }
    
    

    fallback prop 支持在等待组件加载时接受要渲染的任何React元素

    您可以将 Suspense 组件放置在 lazy 组件上方的任何位置

    您甚至可以用一个 Suspense 组件包装多个惰性组件。

    
    import React, { Suspense } from 'react';
    
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    
    const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
    
    function MyComponent() {
      return (
        <div>
          <Suspense fallback={<div>Loading...</div>}>
            <section>
              <OtherComponent />
              <AnotherComponent />
            </section>
          </Suspense>
        </div>
      );
    }
    
    

    Error boundaries

    错误边界

    如果另一个模块无法加载(例如,由于网络故障),它将触发错误

    您可以处理这些错误,以显示良好的用户体验,并通过错误边界管理恢复

    创建错误边界后,您可以在惰性组件上方的任何位置使用它来在出现网络错误时显示错误状态。

    import React, { Suspense } from 'react';
    
    import MyErrorBoundary from './MyErrorBoundary';
    
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
    
    const MyComponent = () => (
      <div>
        <MyErrorBoundary>
          <Suspense fallback={<div>Loading...</div>}>
            <section>
              <OtherComponent />
              <AnotherComponent />
            </section>
          </Suspense>
        </MyErrorBoundary>
      </div>
    );
    
    

    https://reactjs.org/docs/error-boundaries.html

    
    
    

    Route-based code splitting

    基于路由的代码拆分

    React Router & React.lazy

    确定在应用程序中的何处引入代码拆分可能有些棘手
    您要确保选择的位置能够平均拆分捆绑包,但不会破坏用户体验

    路线是一个不错的起点
    网络上的大多数人习惯了页面过渡,需要花费一些时间来加载
    您还倾向于一次重新渲染整个页面,因此您的用户不太可能同时与页面上的其他元素进行交互

    这是一个示例,说明如何使用带有 React.lazy 的 React Router 等库将基于路由的代码拆分为您的应用。

    import React, {
     Suspense, 
     lazy,
    } from 'react';
    
    import {
      BrowserRouter as Router, 
      Route, 
      Switch,
    } from 'react-router-dom';
    
    const Home = lazy(() => import('./routes/Home'));
    const About = lazy(() => import('./routes/About'));
    
    const App = () => (
      <Router>
        <Suspense fallback={<div>Loading...</div>}>
          <Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/about" component={About}/>
          </Switch>
        </Suspense>
      </Router>
    );
    
    

    https://reactjs.org/docs/code-splitting.html#route-based-code-splitting

    react-router

    https://reacttraining.com/react-router/

    Named Exports

    命名的导出

    React.lazy 当前仅支持默认导出

    如果要导入的模块使用命名的导出,则可以创建一个中间模块,将其重新导出为默认模块

    这样可以确保摇树不停,并且不会拉扯未使用的组件

    
    // ManyComponents.js
    export const MyComponent = /* ... */;
    export const MyUnusedComponent = /* ... */;
    
    // MyComponent.js 
    // 中间模块, 导出为默认模块
    export { MyComponent as default } from "./ManyComponents.js";
    
    
    // MyApp.js
    import React, { lazy } from 'react';
    const MyComponent = lazy(() => import("./MyComponent.js"));
    

    webpack

    https://webpack.js.org/guides/code-splitting/

    
    module.exports = {
      entry: {
        main: './src/app.js',
      },
      output: {
        // `filename` provides a template for naming your bundles (remember to use `[name]`)
        filename: '[name].bundle.js',
        // `chunkFilename` provides a template for naming code-split bundles (optional)
        chunkFilename: '[name].bundle.js',
        // `path` is the folder where Webpack will place your bundles
        path: './dist',
        // `publicPath` is where Webpack will load your bundles from (optional)
        publicPath: 'dist/'
      }
    };
    
    

    https://gist.github.com/gaearon/ca6e803f5c604d37468b0091d9959269

    webpack & magic-comments

    https://webpack.js.org/api/module-methods/#magic-comments

    https://webpack.docschina.org/api/module-methods/#magic-comments

    
    // Single target
    import(
      /* webpackChunkName: "my-chunk-name" */
      /* webpackMode: "lazy" */
      /* webpackExports: ["default", "named"] */
      'module'
    );
    
    // Multiple possible targets
    import(
      /* webpackInclude: /.json$/ */
      /* webpackExclude: /.noimport.json$/ */
      /* webpackChunkName: "my-chunk-name" */
      /* webpackMode: "lazy" */
      /* webpackPrefetch: true */
      /* webpackPreload: true */
      `./locale/${language}`
    );
    import(/* webpackIgnore: true */ 'ignored-module.js');
    
    

    babel

    https://babeljs.io/

    https://classic.yarnpkg.com/en/package/@babel/plugin-syntax-dynamic-import

    $ yarn add -D @babel/plugin-syntax-dynamic-import
    
    

    https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import

    $ npm i -D @babel/plugin-syntax-dynamic-import
    
    
    {
      "plugins": ["@babel/plugin-syntax-dynamic-import"]
    }
    
    
    
    // webpack config
    const config = {
      entry: [
        "core-js/modules/es.promise",
        "core-js/modules/es.array.iterator",
        path.resolve(__dirname, "src/main.js"),
      ],
      // ...
    };
    
    // or
    
    // src/main.js
    import "core-js/modules/es.promise";
    import "core-js/modules/es.array.iterator";
    
    // ...
    
    

    https://babeljs.io/blog/2019/07/03/7.5.0#dynamic-import-9552httpsgithubcombabelbabelpull9552-and-10109httpsgithubcombabelbabelpull10109

    https://www.npmjs.com/package/babel-plugin-dynamic-import-node

    https://github.com/airbnb/babel-plugin-dynamic-import-node

    $ yarn add -D babel-plugin-dynamic-import-node
    
    

    .babelrc

    
    {
      "plugins": ["dynamic-import-node"]
    }
    
    

    dynamic import

    https://webpack.js.org/guides/code-splitting/#dynamic-imports

    import("./emoji-component").then(emoji => {
      // 使用 promise 
      console.log(emoji));
    });
    
    

    切换路由

    react-router

    lazy-load

    延迟加载 / 懒加载

    code splitting & dynamic import

    import()类似函数的形式将模块名称作为参数,并返回一个Promise,该Promise始终解析为模块的名称空间对象

    https://github.com/tc39/proposal-dynamic-import

    http://2ality.com/2017/01/import-operator.html#loading-code-on-demand

    https://create-react-app.dev/docs/code-splitting/

    const moduleA = `ESM (code splitting & dynamic import)`;
    
    export { moduleA };
    
    

    这将使 moduleA.js 及其所有唯一依赖项成为单独的块,仅在用户单击“加载”按钮后才加载

    import React, { Component } from 'react';
    
    class App extends Component {
      handleClick = () => {
        import('./moduleA')
          .then(({ moduleA }) => {
            // Use moduleA
          })
          .catch(err => {
            // Handle failure
          });
      };
      render() {
        return (
          <div>
            <button onClick={this.handleClick}>Load</button>
          </div>
        );
      }
    }
    export default App;
    
    

    async / await & promise

    如果愿意,还可以将其与 async / await 语法一起使用

    // async / await 
    
     async handleClick = () => {
       const moduleA = await import('./moduleA');
      
       moduleA.then(({ moduleA }) => {
            // Use moduleA
        })
        .catch(err => {
            // Handle failure
         });
     };
    
    
    

    chunks

    https://create-react-app.dev/docs/production-build

    refs



    ©xgqfrms 2012-2020

    www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!


  • 相关阅读:
    Java面向对象编程之异常处理机制
    LinkedList链式集合
    Java之反射机制
    适配器模式
    QuickHit
    Java之单例模式
    Java面向对象之接口
    多线程
    线程同步
    试题分析
  • 原文地址:https://www.cnblogs.com/xgqfrms/p/13820944.html
Copyright © 2011-2022 走看看