最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Automatically loading externals with Webpack - Stack Overflow

programmeradmin1浏览0评论

I've done some searching but was wondering if there's an elegant solution here. When building a Webpack app, it's mon to have dependencies that don't need to be piled/bundled, like jQuery, React, ReactDOM, Angular, or Bootstrap, to name a few. You can list these in your Webpack config file in an externals object, but externals just assumes that these libraries will be available as namespaced globals at runtime.

This means that for each entry in your externals hash, you also need to toss in a script tag in your HTML. This makes sense if you're referencing an external CDN, but I'm thinking this could be automated if all you want to do is copy some dist file from a library in node_modules.

I've been looking for examples of how to do this but I haven't seen any yet. I messed with external-loader but I haven't had any luck integrating it (the documentation doesn't seem to provide a plete example).

Essentially, this would need to happen:

  1. Libraries that shouldn't be bundled should be added to resolve.alias, e.g. {"react": "react/dist/react.js"}
  2. A loader copies the dist files to the public directory (maybe this could just be done with file-loader?)
  3. An HTML loader or maybe plugin inserts the script tags before the bundle.js script tag

If something like this doesn't exist, I might look into trying to make one; I'm just posting this here to see if anyone might know of a pre-baked solution, as it seems like it'd be a mon problem for building web apps and I figured I'm probably missing something.

I've done some searching but was wondering if there's an elegant solution here. When building a Webpack app, it's mon to have dependencies that don't need to be piled/bundled, like jQuery, React, ReactDOM, Angular, or Bootstrap, to name a few. You can list these in your Webpack config file in an externals object, but externals just assumes that these libraries will be available as namespaced globals at runtime.

This means that for each entry in your externals hash, you also need to toss in a script tag in your HTML. This makes sense if you're referencing an external CDN, but I'm thinking this could be automated if all you want to do is copy some dist file from a library in node_modules.

I've been looking for examples of how to do this but I haven't seen any yet. I messed with external-loader but I haven't had any luck integrating it (the documentation doesn't seem to provide a plete example).

Essentially, this would need to happen:

  1. Libraries that shouldn't be bundled should be added to resolve.alias, e.g. {"react": "react/dist/react.js"}
  2. A loader copies the dist files to the public directory (maybe this could just be done with file-loader?)
  3. An HTML loader or maybe plugin inserts the script tags before the bundle.js script tag

If something like this doesn't exist, I might look into trying to make one; I'm just posting this here to see if anyone might know of a pre-baked solution, as it seems like it'd be a mon problem for building web apps and I figured I'm probably missing something.

Share Improve this question asked Sep 8, 2016 at 23:21 M MillerM Miller 5,68210 gold badges48 silver badges69 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 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./ajax/libs/jquery/1.12.4/jquery.js'
        }
      ],
      {
          basedir: 'node_modules',
          dest: 'lib'
      }),

          new WebpackNotifierPlugin()
    ]
};

Am I missing anything here?

I didn't find a pre-existing solution, so I wrote a plugin to supplement the HtmlWebpackPlugin. It takes an array of externals and appends script/link tags to the HTML file, generates the externals hash, and can use CDNs or local files.

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

If you don't want to add extra package bloat then HtmlWebpackPlugin has templating features, so you could do something like this:

//template.html

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

and then something like this in your webpack config:

//webpack.config.js

const EXTERNALS = [
  {
    name: 'react',
    globalVarName: 'React',
    src: 'https://cdn.example./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,
    }), {}
  ),
}

(You can obviously add any environment customisations/finer details/etc. you want in the webpack config file.)

EDIT:

For some extra panache you could also get the current package versions from your node_modules rather than hard-coding them into the webpack file:

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']
}
发布评论

评论列表(0)

  1. 暂无评论