首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用React Router和Webpack 2如何只在某些路由上需要外部库?

使用React Router和Webpack 2如何只在某些路由上需要外部库?
EN

Stack Overflow用户
提问于 2017-02-13 23:03:53
回答 4查看 2.6K关注 0票数 16

目前正在工作

使用Webpack 2和React Router v4,我已经能够设置工作代码拆分。有一个中间的<AsyncComponent>,它解析promise并返回组件(在github问题上找到的模式)。

下面是一组路由示例:

代码语言:javascript
复制
<Switch>
    <Route 
        path="me" 
        render={(props) => 
            <AsyncComponent promise={ require.ensure([], (require) => require('./modules/Profile'), 'profile') } props={props} />
        } 
    />
    <Route 
        path="credit-card" 
        render={(props) => 
            <AsyncComponent promise={ require.ensure([], (require) => require('./modules/CreditCard'), 'credit-card') } props={props} />
        } 
    />
</Switch>

目标

我想进一步扩展这一点,对于某些路由,只需要,就可以加载额外的库。在上面的示例中,我只想在信用卡路径上获取StripeJS (https://js.stripe.com/v2/)库。

我想强调的是,我可以直接加载条纹到页脚,一切正常工作。这里有多个库,我把它作为一个易于理解的例子来使用。

已尝试

已经尝试了以下几种方法,但收效甚微:

在webpack配置中标记外部库的

  • 。这(正确地)将库标记为外部的,并且不会在请求的解析序列期间尝试捆绑它。然而,期望的是库是手动引入的。
  • 我有过使用伪脚本加载器的想法(当遇到该路由时,手动创建一个具有src属性的<script>,等待它加载,然后让组件完成它的工作。这个不错,但从可维护性的角度来看(如果需要两个或更多的库,我就需要复制笨拙的手动script加载),这真的很糟糕,而且似乎与webpack的“方式”相反。

配置的相关部分

代码语言:javascript
复制
const core = [
    'lodash',
    'react',
    'react-dom',
    'axios',
    'react-router-dom',
];

const config = {
    context: path.resolve(__dirname, './ts_build'),
    node: {
        fs: "empty"
    },
    entry: {
        app: './app.js',
        core: core,
    },
    output: {
        filename: '[name].js',
        chunkFilename: '[name].[id].chunk.js',
        path: path.resolve(__dirname, './../../public'),
        publicPath: 'http://example.org/',
    },
    resolve: {
        modules: [
            path.resolve('./src'),
        ],
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            names: ['core'], 
            minChunks: Infinity,
        }),
        new webpack.NamedModulesPlugin(),
    ],
};
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-03-12 02:09:06

https://github.com/hinok/webpack2-react-router-code-splitting

存储库包含使用动态import()webpack2 + react-router v4 +实现的code splitting,并且只使用loadjs按需加载一次外部库。例如,它加载特定路由的Stripe.js

在存储库中,您可以找到两种方法来进行代码拆分

它是基于官方的Webpack文档和安德鲁·克拉克的要点

在准备该存储库时,我发现@Chris只想为外部CDN上托管的某些路由加载Stripe.js

代码语言:javascript
复制
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['b'], function (b) {
            return (root.amdWebGlobal = factory(b));
        });
    } else {
        root.amdWebGlobal = factory(root.b);
    }
}(this, function (b) {
    return {};
}));

我可以说,UMD包装器是一种标准,但有时人们更喜欢不那么固执己见的包装器,或者他们只是不关心其他环境。我提到它是因为在git的历史中,你可以找到commit called Amdify,它更多地证明了如何模拟AMD环境的概念。最后,我决定删除它,因为它远不是理想的,它没有涵盖所有的用法和边缘情况。

我找不到任何关于集成外部AMD模块或以某种方式使用AMD模块的信息。相反,我发现它根本不能工作。

AMD @mc-zone你应该能够用script.js加载

模块。但这与webpack无关,它之所以有效,是因为AMD就是为此而设计的。因此,您将无法使用这些AMD模块中的webpack功能。webpack要求对构建时间进行静态分析。

作者:@jhns see on github

的webpack并不处理脚本加载。为此,请使用单独的库。即https://github.com/ded/script.js/

作者:@sokra see on github

如果不可能,则不应该使用

(),而是通过像script.js这样的脚本加载器加载它。

作者:@jhns see on github

关于Github的相关问题:

今天我在medium上找到了an article by James Kale关于他的项目react-loadable的信息,这个项目与LazilyLoad组件的功能几乎相同,但承诺

  • 它通过一个动态的require()
  • 支持服务器端渲染它在需要时急切地预装组件

我强烈建议你去看看。

票数 3
EN

Stack Overflow用户

发布于 2017-02-14 12:58:57

如果您使用的是Webpack 2,请在React路由器配置文件中使用import()

代码语言:javascript
复制
export default {
 component: App,
 childRoutes: [
   {
     path: '/',
     getComponent(location, cb) {
       import('external-library-here')
       .then(function(){
         return System.import('pages/Home');
       })
      .then(loadRoute(cb)).catch(errorLoading);
     }
   },
   {
     path: 'blog',
     getComponent(location, cb) {
       import('pages/Blog').then(loadRoute(cb)).catch(errorLoading);
     }
   },
   {
     path: 'about',
     getComponent(location, cb) {
       import('pages/About').then(loadRoute(cb)).catch(errorLoading);
     }
   },
 ]
};

您还可以使用Router组件中的getComponentgetComponents属性来传入专门用于该路由的模块。

票数 0
EN

Stack Overflow用户

发布于 2017-02-23 10:20:24

这个问题中有一些情况应该详细考虑。

让我们开始吧。

观察

  • 您应该将react-router的使用从components改为PlainRoute object,这将使您在进行代码拆分时具有更大的灵活性,并且还可以跳过创建<AsyncComponent> component
  • 我非常确定您的路由中将有更多的嵌套组件,那么如果credit-card路由中的嵌套组件需要库怎么办?

< code >F29

建议

  • 使用你的路由组件作为入口点,所以它不会在单个窗口中成为一个巨大的实现。上面的建议是,你可以添加一个带有你的库依赖项的索引,并在该路由中使用它们(在你的
    • 中,你不应该在代码的任何部分导入这些库,否则一旦你加载了这些库,将它们注入到窗口对象中,这个功能就会破坏
    • 。并且您的嵌套组件将能够全局访问您的库

这是一个尚未实施的建议,但我正在尝试将您的问题引向正确的方向

最后,这是我建议的方法:

代码语言:javascript
复制
import App from 'components/App';

function errorLoading(err) {
  console.error('Dynamic page loading failed', err);
}

function loadRoute(cb) {
  return (module) => cb(null, module.default);
}

function injectLibraries(libraries) {
  Object.keys(libraries).forEach(key => {
    window[key] = libraries[key];
  });
}

export default {
  component: App,
  childRoutes: [
    {
      path: '/(index.html)',
      name: 'home',
      getComponent(location, cb) {
        const importModules = Promise.all([
          import('components/HomePage/'),
          import('components/HomePage/libraries'),
        ]);

        const renderRoute = loadRoute(cb);

        importModules.then(([component, libraries]) => {
          injectLibraries(libraries);
          renderRoute(component);
        });

        importModules.catch(errorLoading);
      },
    },
    {
      path: '/credit-card',
      name: 'credit-card',
      getComponent(nextState, cb) {
        const importModules = Promise.all([
          import('components/CreditCardPage/'),
          import('components/CreditCardPage/libraries'),
        ]);

        const renderRoute = loadRoute(cb);

        importModules.then(([component, libraries]) => {
          injectLibraries(libraries);
          renderRoute(component);
        });

        importModules.catch(errorLoading);
      },
    },
  ],
};

您的库文件应如下所示:

代码语言:javascript
复制
import stripe from 'stripe';

export default {
  stripe 
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42207159

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档