Skip to content
This repository has been archived by the owner on Apr 5, 2021. It is now read-only.

v3.0.0

Compare
Choose a tag to compare
@mmiller42 mmiller42 released this 16 Sep 01:40
· 92 commits to master since this release

What's New in v3.0.0

This is a summary of the differences between v3.0.0 and v2.2.3.

Commits

Show commits
SHA Author Message
e571e48 mmiller42 Starting from scratch
8ef5f07 mmiller42 Bootstrapping
89e94db mmiller42 Initial concept
d880fe5 mmiller42 It works!
b23be30 mmiller42 Documentation and minor fixes
bdefdb6 mmiller42 Match description
729a746 mmiller42 Remove unused package

Changed files

.babelrc

Show changes
@@ -0,0 +1,17 @@
+{
+	"presets": [
+		[
+			"babel-preset-env",
+			{
+				"targets": {
+					"node": "4.3.0"
+				}
+			}
+		]
+	],
+	"plugins": [
+		"babel-plugin-add-module-exports",
+		"babel-plugin-transform-class-properties",
+		"babel-plugin-transform-object-rest-spread"
+	]
+}

.editorconfig

Show changes
@@ -0,0 +1,10 @@
+root = true
+
+[src/**.js]
+indent_style = tab
+indent_size = tab
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+max_line_length = 80

.gitignore

Show changes
@@ -1,46 +1,16 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-
-# Runtime data
-pids
-*.pid
-*.seed
-npm-debug.log
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/
+# OS/IDE files
+.DS_Store
+*#
+*~
+.idea
 
-# Dependency directory
-# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
+# Dependencies
 node_modules
 
-# Optional npm cache directory
-.npm
-
-# Optional REPL history
+# Logs
+*.log
 .node_repl_history
 .node_history
 
-# Redis dumps
-dump.rdb
-
-# IDE and OS files
-.idea
-.tmp
-*#
-*~
-.DS_Store
+# Build files
+lib

LICENSE

Show changes
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2016 Matt Miller
+Copyright (c) 2017 Matt Miller
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

README.ZH-CN.md

Show changes
@@ -1,219 +0,0 @@
-# html-webpack-externals-plugin
-
-本插件提供基本接口加载第三方依赖库增强了[html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin)的不足。
-
-Webpack的开发者们建议在开发过程、构建过程中单独加载第三方依赖库来提升编译速度,以极大的利用浏览器的缓存能力。
-
-本插件允许使用以下2种方式加载第三方css,js 依赖:
-
-* **Absolute URLs.** 这种方式让你更好的利用浏览器的缓存以及CDN带来的好处。在这种情况中,不需要在package.json文件中添加这些依赖,但是依然需要通过require/import声明引入。与URLs对应的script,link标签,也即js和css会被附件到HTML文件。
-* **Local module dist files.** 这种方式让你直接使用本地依赖文件,而不是把它们打包在一起。在构建时,对应路径的配置列表会被从node_modules目录拷贝到HTML中,同理js文件用script标签,css用link标签。
-
-## 安装
-
-\`\`\`sh
-npm install html-webpack-externals-plugin --save-dev
-\`\`\`
-
-## 使用
-
-### 基本例子
-添加到Webpack 配置文件中的\`plugins\`数组中,并放在\`HtmlWebpackPlugin\`后面,实际使用中发现貌似放在前面也可以。
-
-\`\`\`js
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
-
-module.exports = {
-  // ...your Webpack config
-  plugins: [
-    new HtmlWebpackPlugin(),
-    new HtmlWebpackExternalsPlugin(
-      // See the API section
-    );
-  ]
-};
-\`\`\`
-使用这个插件时,不需要再在Webpack配置文件中定义 \`externals\`。插件会在运行时写入。
-
-### 更加详细的例子
-
-\`\`\`js
-//webpack.config.js
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
-
-module.exports = {
-  // ...your Webpack config
-  plugins: [
-    new HtmlWebpackPlugin({
-      filename: 'index.html',
-      template: 'path.to.html.template.name'),
-      lib: ['jquery', 'd3', 'bootstrap.css'],
-      chunks: ['entry-name']
-    }),
-    new HtmlWebpackExternalsPlugin(
-        [
-          {
-              name: 'jquery',
-              var: 'jQuery',
-              path: './jquery/jquery-3.1.1.js'
-          },
-          {
-              name: 'd3',
-              var: 'd3',
-              path: './d3/d3.min.js'
-          },
-          {
-              name: 'Highcharts',
-              var: 'Highcharts',
-              path: './highcharts-5.0.4/highcharts.js'
-          },
-          {
-              name: 'HighchartsMore',
-              var: 'Highcharts',
-              path: './highcharts-5.0.4/highcharts-more.js'
-          },
-          {
-              name: 'bootstrap.css',
-              path: './bootstrap-3.3.7/css/bootstrap.min.css'
-          },
-      ], 
-      {
-          basedir: 'path.to.your.lib.basedir',
-          dest: 'lib'
-      }
-    );
-  ]
-};
-\`\`\`
-
-\`\`\`js
-//输出的html
-//entry.css 是在名为 'entry' 的chunk(entry对应的js文件)里被引入的
-<!-- index.html -->
-<!DOCTYPE HTML>
-<html lang="zh-CN">
-<head>
-  <meta charset="UTF-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
-  <meta name="renderer" content="webkit">
-  <title>XXX</title>
-<link href="lib/bootstrap-3.3.7/css/bootstrap.min.css" rel="stylesheet"><link href="./css/entry.css" rel="stylesheet"></head>
-<body>
-<button id="btn">test</button>
-
-<div id="industryMap"></div>
-<script type="text/javascript" src="lib/jquery/jquery-3.1.1.js"></script><script type="text/javascript" src="lib/d3/d3.min.js"></script><script type="text/javascript" src="./js/entry.js"></script></body>
-</html> 
-\`\`\`
-#### 注意: 插件只会从 HtmlWebpackPlugin 的配置对象中读取 'lib' 属性。如果 'lib' 没有被定义,则在 HtmlWebpackExternalsPlugin 中配置的全部依赖会被附加到 HTML 中。
-
-## API
-
-### new HtmlWebpackExternalsPlugin(externals, options)
-
-#### externals
-
-一个对象数组,每一个对象代表一个外部依赖。每一个对象会包含如下的属性。
-
-\`\`\`js
-[
-  {
-    // 依赖的名称,即被传递到 \`require()\` 或者 \`import\` 声明中的那个名称
-    name: 'react',
-    // JS 库在 \`window\` 对象中暴露的那个变量名称。 比如 \`jQuery\` or \`React\`。
-    // 如果依赖库中没有暴露任何值(比如CSS文件,不需要暴露一个全局变量),省略这个属性也可以。
-    var: 'React',
-    // 用于从 CDN 加载依赖的绝对路径
-    url: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react.js'
-  },
-  {
-    name: 'react',
-    var: 'React',
-    // 可选地,你可以指定你的项目目录下的 \`node_modules\` 目录下的一个目录。
-    //webpack会在构建时拷贝到输出('build'属性)目录
-    path: 'react/dist/react.min.js'
-  }
-]
-\`\`\`
-
-#### options
-
-一个对象,包含了插件需要的属性。这个配置只会应用到从本地目录中读取依赖的情况。(即使用 \`path\` 而不是 \`url\`)
-
-\`\`\`js
-{
-  // 会被解析成本地依赖文件的绝对路径。通常为项目的根目录。用于加载本地依赖。 大多数情况下可以使用 \`__dirname\`
-  basedir: __dirname,
-  // 拷贝本地依赖到 build 目录的那个目录名称。默认为 'vendor'
-  // \`'vendor'\`.
-  dest: 'vendor'
-}
-\`\`\`
-
-## 例子
-
-### webpack.config.js
-
-\`\`\`js
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
-
-module.exports = {
-  // ...your Webpack config
-  plugins: [
-    new HtmlWebpackPlugin(),
-    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'
-        },
-        // Using a locally installed module for a JS library
-        {
-          name: 'react',
-          var: 'React',
-          path: 'react/dist/react.min.js'
-        },
-        // Using a CDN for a library with no export (e.g. a CSS module)
-        {
-          name: 'bootstrap.css',
-          url: 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css'
-        }
-      ],
-      {
-        // 本地依赖的相对路径
-        basedir: __dirname
-      }
-    );
-  ]
-};
-\`\`\`
-
-### index.jsx
-
-\`\`\`js
-import React, {Component} from 'react';
-import $ from 'jquery';
-// 不需要 import 'bootstrap.css', 因为已经被添加到 html 中了
-\`\`\`
-
-注意因为它们是外部依赖,所以它们总是只会被加载一次,不管你是否在你自己的代码中多处使用。意思就是说没必要再在 js 文件中引入 CSS 库了,比如 Bootstrap CSS。
-
-## Assets Required by Library (不好翻译,应该是依赖库需要的额外资源,比如字体资源)
-
-对于本地依赖 (即使用 \`path\` 属性,而不是 \`url\`),有时候需要拷贝依赖库所依赖的额外资源到目标目录(比如 Bootstrap 用到的字体资源)。
-
-最简单的方法就是结合 [CopyWebpackPlugin](https://github.com/kevlened/copy-webpack-plugin) 与 HtmlWebpackExternalsPlugin, 拷贝需要的文件到 build 目录。
-
-在你的 Webpack 配置文件里的 \`plugins\` 数组里,添加下列插件到 HtmlWebpackExternalsPlugin 配置后面。
-
-\`\`\`js
-new CopyWebpackPlugin([
-  {from: 'node_modules/bootstrap/dist/', to: 'vendor/bootstrap/dist/'},
-  {from: 'node_modules/font-awesome/fonts/', to: 'vendor/font-awesome/fonts/'}
-])
-\`\`\`

README.md

Show changes
@@ -1,274 +1,84 @@
-# html-webpack-externals-plugin *DEPRECATED*
+# html-webpack-externals-plugin
 
-I don't advise people to use this plugin, personally. I developed it with the intention of having it keep my code clean, but it's buggy in too many edge cases. I'm finding that it's better (if more verbose), to use a combination of [\`externals\`](https://webpack.github.io/docs/configuration.html#externals), [\`HtmlWebpackPlugin\`](https://github.com/jantimon/html-webpack-plugin), [\`HtmlWebpackIncludeAssetsPlugin\`](https://github.com/jharris4/html-webpack-include-assets-plugin), and [\`CopyWebpackPlugin\`](https://github.com/kevlened/copy-webpack-plugin), like so:
+Webpack plugin that works alongside [\`html-webpack-plugin\`](https://github.com/jantimon/html-webpack-plugin) to use pre-packaged vendor bundles.
 
-\`\`\`js
-  plugins: [
-    // Use CopyWebpackPlugin to copy dist files to your outputPath
-    new CopyWebpackPlugin([
-      { from: 'node_modules/react/dist/react.js', to: 'vendor/js/' },
-      { from: 'node_modules/react-dom/dist/react-dom.js', to: 'vendor/js/' },
-      { from: 'node_modules/redux/dist/redux.js', to: 'vendor/js/' },
-      { from: 'node_modules/semantic-ui-css/semantic.css', to: 'vendor/css/' },
-      // Required assets of your dependencies (such as fonts and images) can be copied too
-      { from: 'node_modules/semantic-ui-css/themes/', to: 'vendor/css/themes/' }
-    ]),
-    // Use HtmlWebpackAssetsPlugin to add asset script/link tags to HTML output
-    new HtmlWebpackIncludeAssetsPlugin({
-      // List of JS and CSS paths (relative to outputPath) to load
-      assets: [
-        'vendor/js/react.js',
-        'vendor/js/react-dom.js',
-        'vendor/js/redux.js',
-        'vendor/css/semantic.css'
-      ],
-      // Insert these assets before the bundle file(s)
-      append: false,
-      // Add hash to end of filename so that if your dependencies update, cache will refresh
-      hash: true
-    }),
-    new HtmlWebpackPlugin({
-      filename: 'index.html',
-      template: 'src/index.html',
-      hash: true
-    })
-  ],
-  // Specify the dependencies to exclude from the bundle since the dist files are being used
-  // keys are the module names, values are the globals exported by the dist files
-  externals: {
-    react: 'React',
-    'react-dom': 'ReactDOM',
-    redux: 'Redux'
-  }
-\`\`\`
-
-While it's a little more redundant, it's more reliable and generally more configurable.
-
-If I end up rewriting this plugin at some point, it will probably just provide an abstraction layer over these other plugins.
-
-Documentation is below, but be warned that this plugin is buggy and somewhat unreliable for a number of edge cases.
+## How it works
 
-***
+This plugin is very simple and just encapsulates two other Webpack plugins to do the heavy lifting. It:
 
-This plugin supplements the fantastic [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) by providing a very basic interface for loading your external dependencies.
-
-Webpack developers advise using externals to speed up compile time during development/builds as well as to leverage the caching capabilities of browsers.
-
-This plugin allows you to load external CSS and JS dependencies with:
-
-* **Absolute URLs.** This approach lets you leverage the caching and speed benefits of CDNs. In this case, the module does not need to be in your dependencies list of your \`package.json\` and require/import statements will still behave as expected. Script/link tags with the given URLs are appended to the HTML.
-* **Local module dist files.** This approach lets you serve dist files of your specified dependencies instead of bundling them. At build time, the listed externals are copied from your \`node_modules\` into your build and script/link tags with relative paths are appended to the HTML.
+1. modifies your Webpack config at runtime to add your vendor modules to the [\`externals\`](https://webpack.js.org/configuration/externals/) property.
+1. runs the [\`copy-webpack-plugin\`](https://github.com/kevlened/copy-webpack-plugin) to copy your vendor module assets into the output path.
+1. runs the [\`html-webpack-include-assets-plugin\`](https://github.com/jharris4/html-webpack-include-assets-plugin) to add your vendor module bundles to the HTML output.
 
 ## Installation
 
 \`\`\`sh
-npm install html-webpack-externals-plugin --save-dev
+npm install --save-dev html-webpack-externals-plugin
 \`\`\`
 
 ## Usage
 
-### Basic
-Add it to the \`plugins\` array of your Webpack configuration, after your \`HtmlWebpackPlugin\` instance.
+Require the plugin in your Webpack config file.
 
 \`\`\`js
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
-
-module.exports = {
-  // ...your Webpack config
-  plugins: [
-    new HtmlWebpackPlugin(),
-    new HtmlWebpackExternalsPlugin(
-      // See the API section
-    );
-  ]
-};
+const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
 \`\`\`
 
-When using this plugin, do *not* define \`externals\` in the Webpack configuration yourself; it will be written by the plugin at runtime.
-
-### More Detail
-
-\`\`\`js
-//webpack.config.js
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
-
-module.exports = {
-  // ...your Webpack config
-  plugins: [
-    new HtmlWebpackPlugin({
-      filename: 'index.html',
-      template: 'path.to.html.template.name'),
-      lib: ['jquery', 'd3', 'bootstrap.css'],
-      chunks: ['entry-name']
-    }),
-    new HtmlWebpackExternalsPlugin(
-        [
-          {
-              name: 'jquery',
-              var: 'jQuery',
-              path: './jquery/jquery-3.1.1.js'
-          },
-          {
-              name: 'd3',
-              var: 'd3',
-              path: './d3/d3.min.js'
-          },
-          {
-              name: 'Highcharts',
-              var: 'Highcharts',
-              path: './highcharts-5.0.4/highcharts.js'
-          },
-          {
-              name: 'HighchartsMore',
-              var: 'Highcharts',
-              path: './highcharts-5.0.4/highcharts-more.js'
-          },
-          {
-              name: 'bootstrap.css',
-              path: './bootstrap-3.3.7/css/bootstrap.min.css'
-          },
-      ], 
-      {
-          basedir: 'path.to.your.lib.basedir',
-          dest: 'lib'
-      }
-    );
-  ]
-};
-\`\`\`
-
-\`\`\`js
-//output html
-//entry.css is imported by chunk 'entry'
-<!-- index.html -->
-<!DOCTYPE HTML>
-<html lang="zh-CN">
-<head>
-  <meta charset="UTF-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
-  <meta name="renderer" content="webkit">
-  <title>XXX</title>
-<link href="lib/bootstrap-3.3.7/css/bootstrap.min.css" rel="stylesheet"><link href="./css/entry.css" rel="stylesheet"></head>
-<body>
-<button id="btn">test</button>
-
-<div id="industryMap"></div>
-<script type="text/javascript" src="lib/jquery/jquery-3.1.1.js"></script><script type="text/javascript" src="lib/d3/d3.min.js"></script><script type="text/javascript" src="./js/entry.js"></script></body>
-</html> 
-\`\`\`
-#### Note: the plugin will get property 'lib' from configuration of HtmlWebpackPlugin, and not get from anywhere. If 'lib' is absent, then all libs will be appended
-
-## API
-
-### new HtmlWebpackExternalsPlugin(externals, options)
-
-#### externals
-
-An array of objects, each of which represents an external. Each object may have a set of properties, which are documented in the following code sample.
+Then instantiate it in the \`plugins\` array, after your instance of \`html-webpack-plugin\`.
 
 \`\`\`js
-[
-  {
-    // The name of the external dependency, i.e. what is passed into \`require()\` calls or \`import\`
-    // statements.
-    name: 'react',
-    // JS library dists typically export their API through a single global variable on the \`window\`
-    // object, e.g. \`jQuery\` or \`React\`. If the external does not export anything (e.g. a CSS
-    // dependency), omit this property.
-    var: 'React',
-    // The absolute URL to use when loading the dependency from a CDN.
-    url: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react.js'
-  },
-  {
-    name: 'react',
-    var: 'React',
-    // Alternatively, you can specify a path to a dist file of one of your packages in \`node_modules\`.
-    // This will copy it to the build directory when Webpack runs.
-    path: 'react/dist/react.min.js'
-  }
+plugins: [
+  new HtmlWebpackPlugin(),
+  new HtmlWebpackExternalsPlugin(
+    // See API section
+  )
 ]
 \`\`\`
 
-#### options
+## API
 
-An object containing configuration options for the plugin. Both options apply only to local externals (i.e. externals that use \`path\` instead of \`url\`).
+The constructor takes a configuration object with the following properties.
 
-\`\`\`js
-{
-  // The absolute path to resolve locally installed externals from. Usually this is your
-  // application's root directory. It is required for loading local externals. Most of the time you
-  // can pass \`__dirname\` to use the current directory.
-  basedir: __dirname,
-  // The directory to copy locally installed externals to within the build directory. Defaults to
-  // \`'vendor'\`.
-  dest: 'vendor'
-}
-\`\`\`
+| Property | Type | Description | Default |
+| --- | --- | --- | --- |
+| \`externals\` | array&lt;object&gt; | An array of vendor modules that will be excluded from your Webpack bundle and added as \`script\` or \`link\` tags in your HTML output. | *None* |
+| \`externals[].module\` | string | The name of the vendor module. This should match the package name, e.g. if you are writing \`import React from 'react'\`, this would be \`react\`. | *None* |
+| \`externals[].entry\` | string \| array&lt;string&gt; | The path, relative to the vendor module directory, to its pre-bundled distro file. e.g. for React, use \`dist/react.js\`, since the file exists at \`node_modules/react/dist/react.js\`. Specify an array if there are multiple CSS/JS files to inject. | *None* |
+| \`externals[].global\` | string \| null | For JavaScript modules, this is the name of the object globally exported by the vendor's dist file. e.g. for React, use \`React\`, since \`react.js\` creates a \`window.React\` global. For modules without an export (such as CSS), omit this property or use \`null\`. | \`null\` |
+| \`externals[].supplements\` | array&lt;string&gt; | For modules that require additional resources, specify globs of files to copy over to the output. e.g. for Bootstrap CSS, use \`['dist/fonts/']\`, since Glyphicon fonts are referenced in the CSS and exist at \`node_modules/bootstrap/dist/fonts/\`. | \`[]\` |
+| \`externals[].append\` | boolean | Set to true to inject this module after your Webpack bundles. | \`false\` |
+| \`hash\` | boolean | Set to true to append the injected module distro paths with a unique hash for cache-busting. | \`false\` |
+| \`outputPath\` | string | The path (relative to your Webpack \`outputPath\`) to store externals copied over by this plugin. | \`vendor\` |
 
 ## Example
 
-### webpack.config.js
-
 \`\`\`js
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
-
-module.exports = {
-  // ...your Webpack config
-  plugins: [
-    new HtmlWebpackPlugin(),
-    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'
-        },
-        // Using a locally installed module for a JS library
-        {
-          name: 'react',
-          var: 'React',
-          path: 'react/dist/react.min.js'
-        },
-        // Using a CDN for a library with no export (e.g. a CSS module)
-        {
-          name: 'bootstrap.css',
-          url: 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css'
-        }
-      ],
-      {
-        // Resolve local modules relative to this directory
-        basedir: __dirname
-      }
-    );
-  ]
-};
-\`\`\`
-
-### index.jsx
-
-\`\`\`js
-import React, {Component} from 'react';
-import $ from 'jquery';
-// No need to import 'bootstrap.css' because it's already been added to the page
-\`\`\`
-
-Note that since they are externals, they are always loaded exactly once, whether they are used in source code or not. So this means that it is unnecessary to import the CSS libraries, like Bootstrap.
-
-## Assets Required by Library
-
-For local externals (i.e. externals that use \`path\` instead of \`url\`), sometimes you need to copy other assets to the dist that the library depends on (e.g. font assets used by Bootstrap).
-
-The easiest way to accomplish this is by complementing the HtmlWebpackExternalsPlugin with the [CopyWebpackPlugin](https://github.com/kevlened/copy-webpack-plugin), which copies files in a directory to the build.
-
-In your Webpack configuration's \`plugins\` array, add the plugin after your HtmlWebpackExternalsPlugin instance.
-
-\`\`\`js
-new CopyWebpackPlugin([
-  {from: 'node_modules/bootstrap/dist/', to: 'vendor/bootstrap/dist/'},
-  {from: 'node_modules/font-awesome/fonts/', to: 'vendor/font-awesome/fonts/'}
-])
+new HtmlWebpackExternalsPlugin({
+  externals: [
+    {
+      // Specify that \`react\` module will be externalized (not bundled)
+      module: 'react',
+      // Copy \`node_modules/react/dist/react.js\` into output and insert \`script\` tag
+      entry: 'dist/react.js',
+      // Specify that the \`react\` module is accessed via \`window.React\`
+      global: 'React',
+    },
+    {
+      module: 'react-dom',
+      entry: 'dist/react-dom.js',
+      global: 'ReactDOM',
+    },
+    {
+      module: 'bootstrap',
+      // Specify multiple entry points to copy into output and insert a \`link\` tag for each
+      entry: ['dist/css/bootstrap.css', 'dist/css/bootstrap-theme.css'],
+      // Specify additional assets to copy into the outputPath, needed by this module
+      supplements: ['dist/fonts/'],
+    },
+  ],
+  // Enable cache-busting on the module entry files
+  hash: true,
+  // Specify the directory within the outputPath to copy externals' assets into
+  outputPath: 'vendors',
+})
 \`\`\`

lib/html-webpack-externals-plugin.js

Show changes
@@ -1,186 +0,0 @@
-'use strict';
-
-var fs = require('fs');
-var path = require('path');
-var resolve = require('require-resolve');
-
-function HtmlWebpackExternalsPlugin (externals, options) {
-	this._externals = externals;
-	this._options = options;
-}
-
-HtmlWebpackExternalsPlugin.prototype.apply = function (compiler) {
-	var self = this;
-	compiler.options.externals = compiler.options.externals || {};
-
-	if (Array.isArray(compiler.options.externals)) {
-		self._externals.forEach(function (external) {
-			var obj = {};
-			obj[external.name] = external.var === undefined ? 'undefined' : external.var;
-			compiler.options.externals.push(obj);
-		});
-	} else if (typeof compiler.options.externals === 'object') {
-		self._externals.forEach(function (external) {
-			compiler.options.externals[external.name] = external.var === undefined ? 'undefined' : external.var;
-		});
-	} else {
-		throw new Error('This plugin only works if the existing \`externals\` is an object or array');
-	}
-
-	var assets = {};
-	self._externals.forEach(function (external) {
-		if (typeof external.name !== 'string') {
-			throw new Error('The external must have a \`name\` string.');
-		}
-
-		if (external.var !== undefined && typeof external.var !== 'string') {
-			throw new Error('The external \`var\` must be a string.');
-		}
-
-		if (external.url !== undefined && external.path !== undefined) {
-			throw new Error('Either \`url\` or \`path\` may be defined for a given external, but not both.');
-		}
-
-		if (external.path !== undefined) {
-			if (typeof external.path !== 'string') {
-				throw new Error('The external \`path\` must be a string.');
-			}
-
-			try {
-				// require-resolve assumes the path given is a file and calls path.dirname()
-				// Adding another layer (just "dir") to the basedir will prevent it from
-				// moving up one level too high in the directory hierarchy.
-				var absPath = resolve(external.path, path.join(self._options.basedir, 'dir')).src;
-				var dest = path.join(self._options.dest || 'vendor', external.path);
-				var stat = fs.statSync(absPath);
-			} catch (fileErr) {
-				var err = new Error('Unable to resolve the external \`path\` \`' + external.path + '\`.');
-				err.originalErr = fileErr;
-				throw err;
-			}
-			assets[dest] = {
-				size: function () {
-					return stat.size;
-				},
-				source: function () {
-					return fs.readFileSync(absPath);
-				}
-			};
-			external._href = dest.replace(/\\/g, '/');
-		} else if (external.url !== undefined) {
-			if (typeof external.url !== 'string') {
-				throw new Error('The external \`url\` must be a string.');
-			}
-
-			external._href = external.url;
-		} else {
-			throw new Error('Either \`url\` or \`path\` must be defined for a given external.');
-		}
-	});
-
-	var externalChunks = self._externals
-		.filter(function (external) {
-			return !/\.css($|\?)$/.test(external._href);
-		})
-		.map(function (external) {
-			return {
-				names: [external.name],
-				files: [external._href]
-			};
-		});
-
-	var externalCssFiles = self._externals
-		.filter(function (external) {
-			return /\.css($|\?)$/.test(external._href);
-		})
-		.map(function (external) {
-			return external._href;
-		});
-
-	compiler.plugin('compilation', function (compilation) {
-		Object.assign(compilation.assets, assets);
-		compilation.plugin('html-webpack-plugin-alter-chunks', function (chunks, options) {
-			if( chunks.length > 0 ){
-				var files = chunks[0].files,
-					matched,
-					addChunks = [];
-				
-				//if includeAll is true, or 'lib' of HtmlWebpackPlugin is undefined, or length is 0, just append all libs
-				if( options.plugin.options.lib === undefined ){
-					var entry = chunks[0].files.shift();
-					chunks[0].files = externalCssFiles.concat(chunks[0].files);
-					chunks[0].files.unshift(entry);
-
-					chunks = externalChunks.concat(chunks);
-				}else{
-					options.plugin.options.lib.filter(function(lib){
-						matched = indexOfArr(lib, self._externals);
-						if( matched ){
-							if( /\.css($|\?)$/.test(matched._href) ){
-								files.push( matched._href );
-							}else{
-								addChunks.push({names: [matched.name], files: matched._href});
-							}
-						}
-					});
-
-					chunks = addChunks.concat(chunks);
-				}
-			}
-			return chunks;
-		});
-
-		compilation.plugin('html-webpack-plugin-alter-asset-tags', function (pluginArgs, callback) {
-			var i = 0, 
-				len = externalCssFiles.length,
-				jlen= pluginArgs.head.length,
-				extractedCss = [],
-			    	headFiles;
-
-			for(; i < len; i++){
-				for( var j = 0; j < jlen; j++ ){
-					if( externalCssFiles[i] === pluginArgs.head[j].attributes.href ){
-						extractedCss.push(j);
-						break;
-					}
-				}
-			}
-
-			//make sure that the order of lib css before the css of module
-            		externalCssFiles = [];
-			for( i = 0, len = extractedCss.length; i < len; i++ ){
-                		externalCssFiles.push( Object.assign( {}, pluginArgs.head[extractedCss[i]] ) );
-			}
-
-            		headFiles = [];
-
-            		for( i = 0, len = pluginArgs.head.length; i < len; i++ ){
-            			if ( extractedCss.indexOf(i) < 0 ) { // if index ist not in files index for ths module, transfer to perveious head files, otherwise remove to be added in front of them later
-            				headFiles.push(pluginArgs.head[i]);
-				}
-			}
-
-			pluginArgs.head = externalCssFiles.concat( headFiles ); // put it back together, css from this lib first
-
-			callback();
-		});
-	});
-};
-
-function indexOfArr(target, sourceArr){
-	var i = 0,
-		len = sourceArr.length,
-		external;
-
-	for(; i < len; i++){
-		external = sourceArr[i];
-
-		if( target === external.name ){
-			return external;
-		}
-	}
-
-	return false;
-}
-
-module.exports = HtmlWebpackExternalsPlugin;

lib/index.js

Show changes
@@ -1,3 +0,0 @@
-'use strict';
-
-module.exports = require('./html-webpack-externals-plugin');

package-lock.json

Inline diff not displayed. View the whole file

package.json

Show changes
@@ -1,26 +1,57 @@
 {
-  "name": "html-webpack-externals-plugin",
-  "version": "2.2.3",
-  "description": "Supplemental plugin for HtmlWebpackPlugin to append script tags for external modules",
-  "main": "./lib/index.js",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/mmiller42/html-webpack-externals-plugin.git"
-  },
-  "keywords": [
-    "htmlwebpackplugin",
-    "webpack",
-    "html",
-    "externals",
-    "script"
-  ],
-  "author": "Matt Miller",
-  "license": "MIT",
-  "bugs": {
-    "url": "https://github.com/mmiller42/html-webpack-externals-plugin/issues"
-  },
-  "homepage": "https://github.com/mmiller42/html-webpack-externals-plugin#readme",
-  "dependencies": {
-    "require-resolve": "0.0.2"
-  }
+	"name": "html-webpack-externals-plugin",
+	"version": "3.0.0",
+	"description": "Webpack plugin that works alongside html-webpack-plugin to use pre-packaged vendor bundles.",
+	"keywords": [
+		"htmlwebpackplugin",
+		"webpack",
+		"html",
+		"externals"
+	],
+	"main": "lib/index.js",
+	"scripts": {
+		"prepack": "npm run build",
+		"precommit": "lint-staged",
+		"build": "rm -rf lib && babel src --out-dir lib --source-maps --copy-files",
+		"watch": "babel src --out-dir lib --source-maps --copy-files --watch"
+	},
+	"lint-staged": {
+		"*.js": [
+			"prettier --write --use-tabs --no-semi --single-quote --trailing-comma es5 'src/**/*.js'",
+			"git add"
+		]
+	},
+	"engines": {
+		"node": ">=4.3.0 <5.0.0 || >=5.10"
+	},
+	"repository": {
+		"type": "git",
+		"url": "git+https://github.com/mmiller42/html-webpack-externals-plugin.git"
+	},
+	"author": "Matt Miller <[email protected]>",
+	"license": "MIT",
+	"bugs": {
+		"url": "https://github.com/mmiller42/html-webpack-externals-plugin/issues"
+	},
+	"homepage": "https://github.com/mmiller42/html-webpack-externals-plugin#readme",
+	"devDependencies": {
+		"babel-cli": "^6.24.1",
+		"babel-core": "^6.25.0",
+		"babel-plugin-add-module-exports": "^0.2.1",
+		"babel-plugin-transform-class-properties": "^6.24.1",
+		"babel-plugin-transform-object-rest-spread": "^6.23.0",
+		"babel-preset-env": "^1.6.0",
+		"husky": "^0.14.3",
+		"lint-staged": "^4.0.1",
+		"prettier": "^1.5.3"
+	},
+	"peerDependencies": {
+		"html-webpack-plugin": "^2.0.0",
+		"webpack": "^2.0.0"
+	},
+	"dependencies": {
+		"ajv": "^5.2.2",
+		"copy-webpack-plugin": "^4.0.1",
+		"html-webpack-include-assets-plugin": "0.0.6"
+	}
 }

src/HtmlWebpackExternalsPlugin.js

Show changes
@@ -0,0 +1,128 @@
+import CopyWebpackPlugin from 'copy-webpack-plugin'
+import HtmlWebpackIncludeAssetsPlugin from 'html-webpack-include-assets-plugin'
+import Ajv from 'ajv'
+
+const ajv = new Ajv()
+const validateConfig = ajv.compile({
+	type: 'object',
+	properties: {
+		externals: {
+			type: 'array',
+			items: {
+				type: 'object',
+				properties: {
+					module: { type: 'string' },
+					entry: {
+						type: ['string', 'array'],
+						items: { type: 'string' },
+						minItems: 1,
+					},
+					global: { type: ['string', 'null'] },
+					supplements: {
+						type: 'array',
+						items: { type: 'string' },
+					},
+					append: { type: 'boolean' },
+				},
+				required: ['module', 'entry'],
+			},
+			minItems: 1,
+		},
+		hash: { type: 'boolean' },
+		outputPath: { type: 'string' },
+	},
+	required: ['externals'],
+})
+
+export default class HtmlWebpackExternalsPlugin {
+	static validateArguments(config) {
+		if (!validateConfig(config)) {
+			throw new TypeError(ajv.errorsText(validateConfig.errors))
+		}
+	}
+
+	constructor(config) {
+		HtmlWebpackExternalsPlugin.validateArguments(config)
+
+		this.assetsToPrepend = []
+		this.assetsToAppend = []
+		this.assetsToCopy = []
+		this.externals = {}
+
+		const { externals, hash = false, outputPath = 'vendor' } = config
+		this.hash = hash
+		this.outputPath = outputPath
+
+		externals.forEach(
+			({ module, entry, global = null, supplements = [], append = false }) => {
+				this.externals[module] = global
+
+				const entries = (Array.isArray(entry) ? entry : [entry]).map(
+					entry => \`${module}/${entry}\`
+				)
+
+				if (append) {
+					this.assetsToAppend = [...this.assetsToAppend, ...entries]
+				} else {
+					this.assetsToPrepend = [...this.assetsToPrepend, ...entries]
+				}
+
+				this.assetsToCopy = [
+					...this.assetsToCopy,
+					...entries,
+					...supplements.map(asset => \`${module}/${asset}\`),
+				]
+			}
+		)
+	}
+
+	apply(compiler) {
+		if (!compiler.options.externals) {
+			compiler.options.externals = this.externals
+		} else if (Array.isArray(compiler.options.externals)) {
+			compiler.options.externals.push(this.externals)
+		} else if (typeof compiler.options.externals === 'object') {
+			compiler.options.externals = {
+				...compiler.options.externals,
+				...this.externals,
+			}
+		}
+
+		const pluginsToApply = []
+
+		pluginsToApply.push(
+			new CopyWebpackPlugin(
+				this.assetsToCopy.map(asset => ({
+					from: \`node_modules/${asset}\`,
+					to: \`${this.outputPath}/${asset}\`,
+				}))
+			)
+		)
+
+		if (this.assetsToPrepend.length) {
+			pluginsToApply.push(
+				new HtmlWebpackIncludeAssetsPlugin({
+					assets: this.assetsToPrepend.map(
+						asset => \`${this.outputPath}/${asset}\`
+					),
+					append: false,
+					hash: this.hash,
+				})
+			)
+		}
+
+		if (this.assetsToAppend.length) {
+			pluginsToApply.push(
+				new HtmlWebpackIncludeAssetsPlugin({
+					assets: this.assetsToAppend.map(
+						asset => \`${this.outputPath}/${asset}\`
+					),
+					append: true,
+					hash: this.hash,
+				})
+			)
+		}
+
+		pluginsToApply.forEach(plugin => plugin.apply(compiler))
+	}
+}

src/index.js

Show changes
@@ -0,0 +1,3 @@
+import HtmlWebpackExternalsPlugin from './HtmlWebpackExternalsPlugin'
+
+export default HtmlWebpackExternalsPlugin