【问题标题】:Routes chunks are bundling external scripts in every chunk路由块在每个块中捆绑外部脚本
【发布时间】:2017-11-22 14:25:01
【问题描述】:

在我的 webpack 中,我使用了 externals,其中包含 React、React Dom、Redux 等。

现在,当我实现路由分块时,生成的每个块都会再次重新捆绑外部脚本,所以最终我的包大小非常大。

如何避免我的各个块不重新捆绑外部脚本并从外部使用它们。

编辑

使用https://chrisbateman.github.io/webpack-visualizer/,我可以看到我所有的块都捆绑了公共库——这些库实际上应该来自webpack中的externals

编辑 2

webpack 文件

var path = require('path');
var webpack = require('webpack');

module.exports = {

  entry: ['./src/containers/AppContainer', './src/index'],

  devtool: 'cheap-module-source-map',

  output: {
    path: __dirname + '/dist',
    publicPath: 'public/',
    filename: 'bundle.js',
    chunkFilename: '[name].[id].chunk.[chunkhash].js',
    libraryTarget: 'umd'
  },

  target: 'web',

  externals: {
    antd: 'antd',
    react: 'react',
    'react-dom': 'react-dom',
    'react-router': 'react-router',
    redux: 'redux',
    'react-redux': 'react-redux',
    immutable: 'immutable',
  },

  resolve: {
    modules: [
      path.join(__dirname, '../node_modules')
    ],
    extensions: ['.js', '.jsx', '.json'],
    alias:{
      constants: path.resolve(__dirname, './src/constants'),
      actions: path.resolve(__dirname, './src/actions'),
      styles: path.resolve(__dirname, './src/styles'),
      utils: path.resolve(__dirname, './src/utils')
    }
  },

  resolveLoader: {
    modules: [
      path.join(__dirname, '../node_modules')
    ]
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    }),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      comments: false
    })
  ]

  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          // Ignore local .babelrc files
          babelrc: false,
          presets: [
            ['es2015', { modules: false }],
            'react'
          ],
          plugins: [
            'react-html-attrs',
            'transform-class-properties',
            'transform-decorators-legacy',
            'transform-object-rest-spread',
            [
              'import', {
                libraryName: 'antd'
              }
            ]
          ]
        }
      },
      { test: /\.png$/, loader: 'file-loader' },
      {
        test: /\.s?css$/i,
        use: [
          'style-loader',
          'css-loader'
         ]
      },
      {
        test: /\.s?less$/i,
        exclude:'/node_modules/',
        use: [
          'style-loader',
          'css-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|woff|woff2|eot|ttf|svg)$/,
        loader: 'url-loader',
        options: {
          limit: 100000
        }
      },
      {
        test: /\.eot\?iefix$/,
        loader: 'url-loader',
        options: {
          limit: 100000
        }
      },
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
        options: {
          configFile: './eslint/.eslintrc',
          failOnWarning: false,
          failOnError: false
        }
      }
    ]
  }
};

路线文件

import React from 'react';
import { Route, IndexRoute } from 'react-router';

export default (
  <Route path='/base/'
    getComponent={ (location, callback) => {
      require.ensure([], function (require) {
        callback(null, require('./containers/AppContainer').default);
      });
    } }>

    <Route path='/route1'
      getComponent={ (location, callback) => {
        require.ensure([], function (require) {
          callback(null,
            require('./containter1')
            .default);
        });
      } }
    />

    <Route path='/route2'
      getComponent={ (location, callback) => {
        require.ensure([], function (require) {
          callback(null,
            require('./container2')
            .default);
        });
      } }
    />

    <Route path='/route3'
      getComponent={ (location, callback) => {
        require.ensure([], function (require) {
          callback(null,
            require('./container3')
            .default);
        });
      } }
    />
  </Route>
);

【问题讨论】:

  • 您实际上是在单独的路由/块中导入这些库吗? import React from 'react'。使用 externals 无需导入库
  • 是的,我是。在我所有的块中,我都在使用import React from 'react'。我在 webpack 中的外部组件也已经有了 react 等。所以我的包在技术上不应该在块中包含 React ......有什么想法吗?
  • @Ematipico 如果我不包含块中的库,则会引发编译错误
  • 因此,如果您使用外部组件,则不需要执行import React from 'react'。那么您的 webpack 配置可能有问题吗?可以分享一下代码吗?
  • @Ematipico import React from 'react' 必须在吗?否则它将如何解决 React.Component?我尝试删除它,但它在 webpack 构建期间给出了编译错误。

标签: reactjs webpack webpack-2 code-splitting webpack-externals


【解决方案1】:

尝试像这样更改您的外部部分:

externals: {
    React: require.resolve('react'),
    'window.React': require.resolve('react'),
    ReactDOM: require.resolve('react-dom'),
    'window.ReactDOM': require.resolve('react-dom')
}

另外,从您的代码中删除 import React from 'react'。只需使用React

编辑

抱歉,我编辑了我的答案。才意识到我的错误。我更改了代码。外部变量中的键将是全局变量的名称。通常将它放在 window 对象中也更安全

【讨论】:

  • 没用....同样,当我删除 import React from 'react' 时,它会给出错误,即 React 未定义,因为我的组件正在使用 extends React.Component
  • 这是我在浏览器控制台上得到的 ReferenceError: React is not defined
  • 我不明白为什么它不起作用。你在导入你的包之前导入你的库吗?我指的是你的index.html
  • 是的,当然,库是在包含捆绑包之前加载的。
  • 你实际上可以在你的开发者工具控制台中看到 React 对象吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 2015-07-28
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 2015-06-13
相关资源
最近更新 更多