diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index d66adb7..0000000
--- a/jest.config.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/** @type {import('@jest/types').Config.InitialOptions} */
-const config = {
- testEnvironment: 'node',
- verbose: true,
- testMatch: [
- '**/__tests__/**/*.js',
- '**/?(*.)+(spec|test).js',
- '**/test/*.js',
- ],
-};
-module.exports = config;
diff --git a/readme.md b/readme.md
index d6236b6..c938762 100644
--- a/readme.md
+++ b/readme.md
@@ -202,6 +202,19 @@ Default: `'module-to-cdn'`
Allow you to define a custom module resolver, it can either be a `function` or an npm module.
The resolver should return (or resolve as a Promise) either `null` or an `object` with the keys: `name`, `var`, `url`, `version`.
+#### options.html
+Type: `boolean`
+Default: `!loadScripts` (`true`, unless `options.loadScripts` is true)
+
+Inject the CDN script tags into the `HtmlWebpackPlugin`, if available
+
+#### options.loadScripts
+Type: `boolean`
+Default: `false`
+
+Instead of expecting the scripts to already be loaded via a `` in the html, load them dynamically.
+Uses [webpack externalsType.script](https://webpack.js.org/configuration/externals/#externalstypescript)
+
## Related
diff --git a/src/declarations.d.ts b/src/declarations.d.ts
deleted file mode 100644
index 52504d8..0000000
--- a/src/declarations.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-declare module 'webpack/lib/ExternalModule' {
- import { ExternalModule as ExternalModuleType } from 'webpack';
- declare class ExternalModule extends ExternalModuleType {}
- export default ExternalModule;
-}
diff --git a/src/index.ts b/src/index.ts
index 7bbec9d..d194ed7 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,8 +1,8 @@
import type HtmlWebpackPlugin from 'html-webpack-plugin';
import readPkgUp from 'read-pkg-up';
import resolvePkg from 'resolve-pkg';
+import { ExternalModule } from 'webpack';
import type { Compiler } from 'webpack';
-import ExternalModule from 'webpack/lib/ExternalModule';
import getResolver from './get-resolver';
import { CdnModuleInfo, CdnModuleResolver, PluginOptions } from './types';
@@ -28,12 +28,23 @@ export default class DynamicCdnWebpackPlugin {
verbose: boolean;
resolver: CdnModuleResolver;
modulesFromCdn: { [modulePath: string]: CdnModuleInfo };
+ loadScripts: boolean;
htmlWebpackPlugin?: typeof HtmlWebpackPlugin;
+
constructor(
options: PluginOptions = {},
htmlWebpackPlugin?: typeof HtmlWebpackPlugin | false
) {
- const { disable = false, env, exclude, only, verbose, resolver } = options;
+ const {
+ disable = false,
+ env,
+ exclude,
+ only,
+ verbose,
+ resolver,
+ loadScripts = false,
+ html = !loadScripts,
+ } = options;
if (exclude && only) {
throw new Error("You can't use 'exclude' and 'only' at the same time");
}
@@ -44,9 +55,9 @@ export default class DynamicCdnWebpackPlugin {
this.only = only;
this.verbose = verbose === true;
this.resolver = getResolver(resolver);
+ this.loadScripts = loadScripts;
this.modulesFromCdn = {};
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- this.htmlWebpackPlugin = htmlWebpackPlugin || undefined;
+ this.htmlWebpackPlugin = (html && htmlWebpackPlugin) || undefined;
// Support for old way without passing htmlWebpackPlugin as an argument
if (htmlWebpackPlugin === undefined) {
@@ -71,10 +82,14 @@ export default class DynamicCdnWebpackPlugin {
if (!moduleRegex.test(modulePath)) return;
// Use recognized CDN module if found
- const varName = await this.addModule(contextPath, modulePath, { env });
- return typeof varName === 'string'
- ? new ExternalModule(varName, 'var', modulePath)
- : undefined;
+ const info = await this.addModule(contextPath, modulePath, { env });
+ if (!info) return;
+
+ const varName = info.var;
+
+ return this.loadScripts
+ ? new ExternalModule([info.url, varName], 'script', modulePath)
+ : new ExternalModule(varName, 'var', modulePath);
});
});
@@ -116,7 +131,7 @@ export default class DynamicCdnWebpackPlugin {
contextPath: string,
modulePath: string,
{ env }: { env: string }
- ) {
+ ): Promise {
const isModuleExcluded =
this.exclude.includes(modulePath) ||
(this.only && !this.only.includes(modulePath));
@@ -146,7 +161,7 @@ export default class DynamicCdnWebpackPlugin {
const isModuleAlreadyLoaded = Boolean(this.modulesFromCdn[modulePath]);
if (isModuleAlreadyLoaded) {
const isSameVersion = this.modulesFromCdn[modulePath].version === version;
- return isSameVersion ? this.modulesFromCdn[modulePath].var : false;
+ return isSameVersion ? this.modulesFromCdn[modulePath] : false;
}
const cdnConfig = await this.resolver(modulePath, version, { env });
@@ -180,6 +195,6 @@ export default class DynamicCdnWebpackPlugin {
}
this.modulesFromCdn[modulePath] = cdnConfig;
- return cdnConfig.var;
+ return cdnConfig;
}
}
diff --git a/src/types.ts b/src/types.ts
index 325ae7a..2590ec6 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -22,12 +22,35 @@ export interface CdnModuleInfo {
}
export interface PluginOptions {
+ /** Useful when working offline, will fallback to webpack normal behaviour */
disable?: boolean;
+ /**
+ * Determine if it should load the development or the production version of modules
+ * @default `mode`
+ */
env?: string;
+ /** List the only modules that should be served by the cdn */
only?: string[];
+ /** List the modules that will always be bundled (not be served by the cdn) */
exclude?: string[];
+ /** Log whether the library is being served by the cdn or is bundled */
verbose?: boolean;
+ /**
+ * Allow you to define a custom module resolver, it can either be a `function` or an npm module.
+ * The resolver should return (or resolve as a Promise) either `null` or an `object` with the keys: `name`, `var`, `url`, `version`.
+ * @default require('module-to-cdn')
+ */
resolver?: string | CdnModuleResolver;
+ /**
+ * Inject the CDN script tags into the `HtmlWebpackPlugin`, if available
+ * @default !loadScripts // (`true`, unless `options.loadScripts` is true)
+ */
+ html?: boolean;
+ /**
+ * Instead of expecting the scripts to already be loaded via a `` in the html, load them dynamically.
+ * @see https://webpack.js.org/configuration/externals/#externalstypescript Uses webpack externalsType.script
+ */
+ loadScripts?: boolean;
}
declare module 'webpack' {