externals的正确使用姿势?

1.我在配置文件中使用了下面代码:

externals: {
    'react': 'React',
    'react-dom': 'ReactDOM'
}

2.使用外链引用时没有问题,下面这样:

<script src="./react.min.js"></script>
<script src="./react-dom.min.js"></script>
<script src="./js/index.bundle.js"></script>

3.但我想把react.min.js和react-dom.min.js合并成一个文件,以后还有Jquery,我想把这三个都合并成一个文件;

4.于是使用webpack单独把这2个文件打包了,可是在页面引用时报错:

index.bundle.js:102 Uncaught ReferenceError: React is not defined

寻觅很久没有找到对策

下面是我的配置,需要说明的是我用了两个配置文件,一个是用来开发,另一个是用来打包react.min.js和react-dom.min.js这种文件的:

// 用来打包react.min.js和react-dom.min.js
var path = require('path');
var webpack = require('webpack');
var NODE_DIR = path.resolve(__dirname, 'node_modules');

module.exports = {
  entry: {
    lib: ['react', 'react-dom']
  },
  resolve: {
    alias: {
      'react': path.join(NODE_DIR, 'react/dist/react.min.js'),
      'react-dom': path.join(NODE_DIR, 'react-dom/dist/react-dom.min.js')
    }
  },
  plugins: [
    new webpack.ProvidePlugin({
      React: 'react',
      ReactDOM: 'react-dom'
    }),
    new webpack.optimize.CommonsChunkPlugin({
        name: 'lib',
        filename: 'lib.js'
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ],
  output: {
    path: 'build',
    filename: 'lib.js'
  }
};
// 这个是用来开发的配置
var path = require('path');
var webpack = require('webpack');
var NODE_DIR = path.resolve(__dirname, 'node_modules');

module.exports = {
  entry: {
    // lib: ['react', 'react-dom'],
    index: './src/app/index.js'
  },
  resolve: {
    // root: path.join(__dirname, 'src'),
    // alias: {
    //   'react': path.join(NODE_DIR, 'react/dist/react.min.js'),
    //   'react-dom': path.join(NODE_DIR, 'react-dom/dist/react-dom.min.js')
    // },
    extensions: ['', '.js', '.jsx']
  },
  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM'
  },
  module: {
    // 配置了这个报错 --require is not defined
    // noParse: [
    //   path.join(NODE_DIR, 'react/dist/react.min.js'),
    //   path.join(NODE_DIR, 'react-dom/dist/react-dom.min.js')
    // ],
    loaders: [
      {
        test: /\.js?$/,
        include: path.resolve(__dirname, 'src'),
        loader: 'babel',
        query: {
          // plugins: 'transform-runtime',
          presets: ['es2015', 'stage-0', 'react']
        }
      }
    ]
  },
  plugins: [
    // new webpack.ProvidePlugin({
    //   React: 'react',
    //   ReactDOM: 'react-dom'
    // }),
    // new webpack.optimize.CommonsChunkPlugin({
    //     name: 'lib',
    //     filename: 'lib.js'
    // })
  ],
  output: {
    path: 'build/js',
    filename: 'index.bundle.js'
  }
};

代码已经同步到这里

阅读 17.1k
2 个回答
  1. webpack 打包默认是非全局的,自己这样打包的 lib 并没有全局加入 React 等库,想输出成 library 的话可以用 output.library 和 output.libraryTarget 来达到目的。

  2. 其实不必为了 lib 单独用一个配置的,而且打包 lib.js 中的 CommonsChunkPlugin 其实并没有什么用处。这种情况个人觉得不用 externels,使用 CommonsChunkPlugin 提取所有 entry 的公用 module 就可以了。

不是很清楚你的目的,
这里我猜测你是想在生产环境使用压缩过的min.js而不是未压缩的js。
可以使用resolve.alias方法来让webpack加载你指定路径的文件。

var path = require('path');
var node_modules = path.resolve(__dirname, 'node_modules');
var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');

config = {
    entry: ['webpack/hot/dev-server', path.resolve(__dirname, 'app/main.js')],
    resolve: {
        alias: {
          'react': pathToReact
        }
    },
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'bundle.js',
    },
    module: {
        loaders: [{
            test: /\.jsx?$/,
            loader: 'babel'
        }],
        noParse: [pathToReact]
    }
};

module.exports = config;
resolve.alias:每当 "react" 在代码中被引入,它会使用压缩后的 React JS 文件,而不是到 node_modules 中找。
module.noParse:每当 Webpack 尝试去解析那个压缩后的文件,我们阻止它,因为这不必要。
优化版
var webpack = require('webpack');
var path = require('path');
var node_modules_dir = path.join(__dirname, 'node_modules');

var deps = [
  'react/dist/react.min.js',
  'react-router/dist/react-router.min.js',
  'moment/min/moment.min.js',
  'underscore/underscore-min.js',
];

var config = {
  entry: ['webpack/hot/dev-server', './app/main.js'],
  output: {
    path: path.resolve(__dirname, './build'),
    filename: 'bundle.js'
  },
  resolve: {
    alias: {}
  },
  module: {
    noParse: [],
    loaders: []
  }
};

// Run through deps and extract the first part of the path, // as that is what you use to require the actual node modules // in your code. Then use the complete path to point to the correct// file and make sure webpack does not try to parse it// 通过在第一部分路径的依赖和解压// 就是你像引用 node 模块一样引入到你的代码中// 然后使用完整路径指向当前文件,然后确认 Webpack 不会尝试去解析它

deps.forEach(function (dep) {
  var depPath = path.resolve(node_modules_dir, dep);
  config.resolve.alias[dep.split(path.sep)[0]] = depPath;
  config.module.noParse.push(depPath);
});

module.exports = config;
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题