使用Webpack自动加载外部

时间:2016-09-08 23:21:05

标签: javascript reactjs webpack

我已经做了一些搜索,但想知道这里是否有一个优雅的解决方案。在构建Webpack应用程序时,通常需要编译/捆绑不需要的依赖项,例如jQuery,React,ReactDOM,Angular或Bootstrap,仅举几例。您可以在externals对象的Webpack配置文件中列出这些,但外部只假设这些库在运行时可用作命名空间全局变量。

这意味着对于externals哈希中的每个条目,您还需要在HTML中添加脚本标记。如果您引用外部CDN,这是有道理的,但我想如果您只想从node_modules中的库复制一些dist文件,这可以自动化。

我一直在寻找如何做到这一点的例子,但我还没有见过。我跟external-loader搞砸了但是我没有运气整合它(文档似乎没有提供完整的例子)。

基本上,这需要发生:

  1. 不应捆绑的图书馆应添加到resolve.alias,例如{"react": "react/dist/react.js"}
  2. 加载程序将dist文件复制到公共目录(也许这可以通过file-loader完成?)
  3. HTML加载器或插件可以在bundle.js脚本标记
  4. 之前插入脚本标记

    如果这样的事情不存在,我可能会尝试制作一个;我只是在这里张贴这个,看看是否有人可能知道预先解决的解决方案,因为它似乎是构建网络应用程序的常见问题,我想我可能会遗漏一些东西

3 个答案:

答案 0 :(得分:2)

var path = require("path");
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var helpers = require('./helpers');

var WebpackNotifierPlugin = require('webpack-notifier');

module.exports = {
    entry: {
        'index-ref': './app/index-ref.ts',
        'vendor': './app/vendor.ts',
        'app': './app/main.ts',
    },

    resolve: {
        extensions: ['', '.ts', '.js']
    },

    module: {
        loaders: [
          {
              test: /\.ts$/,
              loaders: ['awesome-typescript-loader', 'angular2-template-loader']
          },
          {
              test: /\.html$/,
              loader: 'html'
          },
          {
              test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
              loader: 'file?name=assets/[name].[hash].[ext]'
          },
          {
              test: /\.css$/,
              exclude: helpers.root('app'),
              loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
          },
          {
              test: /\.css$/,
              include: helpers.root('app'),
              loader: 'raw'
          }
        ]
    },

    plugins: [
      new webpack.optimize.CommonsChunkPlugin({
          name: ['app', 'vendor', 'index-ref']
      }),

      new HtmlWebpackPlugin({
          filename: '../index.html',
          template: 'template' + '/default.html',
          lib: ['jQuery'],
          chunks: ['entry-name']
      }),
      new HtmlWebpackExternalsPlugin([
        // Using a CDN for a JS library 
        {
            name: 'jquery',
            var: 'jQuery',
            url: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js'
        }
      ],
      {
          basedir: 'node_modules',
          dest: 'lib'
      }),

          new WebpackNotifierPlugin()
    ]
};

我在这里遗漏了什么吗?

答案 1 :(得分:1)

我没有找到预先存在的解决方案,所以我写了一个插件来补充HtmlWebpackPlugin。它需要一组外部,并将脚本/链接标记附加到HTML文件,生成外部哈希,并可以使用CDN或本地文件。

https://github.com/mmiller42/html-webpack-externals-plugin

答案 2 :(得分:0)

如果您不想添加额外的包膨胀,那么 HtmlWebpackPlugin 具有模板功能,因此您可以执行以下操作:

//template.html

<html>
  <head>
     <%= htmlWebpackPlugin.options.externals %>
  </head>
  ...
</html>

然后在你的 webpack 配置中是这样的:

//webpack.config.js

const EXTERNALS = [
  {
    name: 'react',
    globalVarName: 'React',
    src: 'https://cdn.example.com/react@18',
  },
  ...
]



module.exports = {
  ...,
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'template.html',
      externals: EXTERNALS.reduce(
        (scripts, external) => (
          `${scripts}<script src="${external.src}"></script>`
        ), ''
      )
    })
  ],
  externals: EXTERNALS.reduce(
    (res, external) => ({
      ...res,
      [external.name]: external.globalVarName,
    }), {}
  ),
}

(你显然可以在 webpack 配置文件中添加任何你想要的环境定制/更精细的细节/等。)

编辑:

对于一些额外的华丽,您还可以从 node_modules 获取当前包版本,而不是将它们硬编码到 webpack 文件中:

const fs = require('fs')

function getPackageVersion(packageName) {
  const pkgPath = `node_modules/${packageName}`
  const pkg = JSON.parse(fs.readFileSync(`${pkgPath}/package.json`, 'utf8'))
  return pkg['version']
}