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

v3.1.0

Choose a tag to compare

@mmiller42 mmiller42 released this 16 Sep 01:40
· 87 commits to master since this release

What's New in v3.1.0

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

Commits

Show commits
SHA Author Message
09bfaec mmiller42 Adding roadmap
ec84b02 mmiller42 Allow publicPath to be overridden
76a32fc mmiller42 Allow URLs to be specified
bbfb624 mmiller42 Clean up validateConfig
781cc65 mmiller42 3.1.0

Changed files

README.md

Show changes
@@ -43,12 +43,13 @@ The constructor takes a configuration object with the following properties.
 | --- | --- | --- | --- |
 | \`externals\` | array<object> | 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<string> | 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[].entry\` | string \| array<string> | 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. To use a CDN instead, simply use a fully qualified URL beginning with \`http://\`, \`https://\`, or \`//\`. | *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<string> | 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\` |
+| \`publicPath\` | string \| null | Override Webpack config's \`publicPath\` for the externals files, or \`null\` to use the default \`output.publicPath\` value. | \`null\` |
 
 ## Example
 

ROADMAP.md

Show changes
@@ -0,0 +1,7 @@
+# v3.0.0 Roadmap
+
+* [ ] Support CDNs in addition to copying local modules to the build
+* [ ] Support ways to manually specify asset type (e.g. for when URLs don't end in \`.css\` or \`.js\`) -- may be dependent on html-webpack-include-assets-plugin
+* [ ] Allow more flexibility in how files are copied to the public output via copy-webpack-plugin
+* [x] Allow overriding of output \`publicPath\`
+* [ ] Support specifying which HTML files are affected by the plugin in the case of multiple instances of html-webpack-plugin

package-lock.json

Inline diff not displayed. View the whole file

package.json

Show changes
@@ -1,6 +1,6 @@
 {
 	"name": "html-webpack-externals-plugin",
-	"version": "3.0.0",
+	"version": "3.1.0",
 	"description": "Webpack plugin that works alongside html-webpack-plugin to use pre-packaged vendor bundles.",
 	"keywords": [
 		"htmlwebpackplugin",
@@ -13,7 +13,7 @@
 		"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"
+		"watch": "npm run build -- --watch"
 	},
 	"lint-staged": {
 		"*.js": [

src/HtmlWebpackExternalsPlugin.js

Show changes
@@ -2,44 +2,49 @@ 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' },
+export default class HtmlWebpackExternalsPlugin {
+	static validateArguments = (() => {
+		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'],
 					},
-					append: { type: 'boolean' },
+					minItems: 1,
 				},
-				required: ['module', 'entry'],
+				hash: { type: 'boolean' },
+				outputPath: { type: 'string' },
+				publicPath: { type: ['string', 'null'] },
 			},
-			minItems: 1,
-		},
-		hash: { type: 'boolean' },
-		outputPath: { type: 'string' },
-	},
-	required: ['externals'],
-})
+			required: ['externals'],
+		})
 
-export default class HtmlWebpackExternalsPlugin {
-	static validateArguments(config) {
-		if (!validateConfig(config)) {
-			throw new TypeError(ajv.errorsText(validateConfig.errors))
+		return config => {
+			if (!validateConfig(config)) {
+				throw new TypeError(ajv.errorsText(validateConfig.errors))
+			}
 		}
-	}
+	})()
+
+	static URL_ENTRY = /^(http:|https:)?\/\//
 
 	constructor(config) {
 		HtmlWebpackExternalsPlugin.validateArguments(config)
@@ -49,17 +54,30 @@ export default class HtmlWebpackExternalsPlugin {
 		this.assetsToCopy = []
 		this.externals = {}
 
-		const { externals, hash = false, outputPath = 'vendor' } = config
+		const {
+			externals,
+			hash = false,
+			outputPath = 'vendor',
+			publicPath = null,
+		} = config
 		this.hash = hash
 		this.outputPath = outputPath
+		this.publicPath = publicPath
 
 		externals.forEach(
 			({ module, entry, global = null, supplements = [], append = false }) => {
 				this.externals[module] = global
 
-				const entries = (Array.isArray(entry) ? entry : [entry]).map(
-					entry => \`${module}/${entry}\`
-				)
+				const localEntries = []
+
+				const entries = (Array.isArray(entry) ? entry : [entry]).map(entry => {
+					if (HtmlWebpackExternalsPlugin.URL_ENTRY.test(entry)) {
+						return entry
+					}
+					const localEntry = \`${module}/${entry}\`
+					localEntries.push(localEntry)
+					return localEntry
+				})
 
 				if (append) {
 					this.assetsToAppend = [...this.assetsToAppend, ...entries]
@@ -69,7 +87,7 @@ export default class HtmlWebpackExternalsPlugin {
 
 				this.assetsToCopy = [
 					...this.assetsToCopy,
-					...entries,
+					...localEntries,
 					...supplements.map(asset => \`${module}/${asset}\`),
 				]
 			}
@@ -88,6 +106,11 @@ export default class HtmlWebpackExternalsPlugin {
 			}
 		}
 
+		const publicPath =
+			this.publicPath == null
+				? compiler.options.output.publicPath
+				: this.publicPath
+
 		const pluginsToApply = []
 
 		pluginsToApply.push(
@@ -99,29 +122,26 @@ export default class HtmlWebpackExternalsPlugin {
 			)
 		)
 
-		if (this.assetsToPrepend.length) {
-			pluginsToApply.push(
-				new HtmlWebpackIncludeAssetsPlugin({
-					assets: this.assetsToPrepend.map(
-						asset => \`${this.outputPath}/${asset}\`
-					),
-					append: false,
-					hash: this.hash,
-				})
-			)
+		const createAssetsPlugin = (assets, append) => {
+			if (assets.length) {
+				pluginsToApply.push(
+					new HtmlWebpackIncludeAssetsPlugin({
+						assets: assets.map(
+							asset =>
+								HtmlWebpackExternalsPlugin.URL_ENTRY.test(asset)
+									? asset
+									: \`${publicPath}${this.outputPath}/${asset}\`
+						),
+						append,
+						hash: this.hash,
+						publicPath: '',
+					})
+				)
+			}
 		}
 
-		if (this.assetsToAppend.length) {
-			pluginsToApply.push(
-				new HtmlWebpackIncludeAssetsPlugin({
-					assets: this.assetsToAppend.map(
-						asset => \`${this.outputPath}/${asset}\`
-					),
-					append: true,
-					hash: this.hash,
-				})
-			)
-		}
+		createAssetsPlugin(this.assetsToPrepend, false)
+		createAssetsPlugin(this.assetsToAppend, true)
 
 		pluginsToApply.forEach(plugin => plugin.apply(compiler))
 	}