@elementor/externalize-wordpress-assets-webpack-plugin 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ # [0.3.0](https://github.com/elementor/elementor-packages/compare/@elementor/externalize-wordpress-assets-webpack-plugin@0.2.1...@elementor/externalize-wordpress-assets-webpack-plugin@0.3.0) (2023-07-11)
7
+
8
+
9
+ ### Features
10
+
11
+ * **webpack-plugins:** simplify logic ([#78](https://github.com/elementor/elementor-packages/issues/78)) ([e4cadc0](https://github.com/elementor/elementor-packages/commit/e4cadc06be61450437274610e65b9d92eb245844))
12
+
13
+
14
+
15
+
16
+
17
+ ## 0.2.1 (2023-07-02)
18
+
19
+ **Note:** Version bump only for package @elementor/externalize-wordpress-assets-webpack-plugin
@@ -0,0 +1,23 @@
1
+ import { ExternalsPlugin, Compiler } from 'webpack';
2
+
3
+ type Global = string | string[];
4
+ type RequestToGlobalMap = Array<{
5
+ request: string | RegExp;
6
+ global: Global;
7
+ }>;
8
+
9
+ type Options = {
10
+ type: string;
11
+ global?: (entryName: string) => Global;
12
+ map: RequestToGlobalMap;
13
+ };
14
+ declare class ExternalizeWordPressAssetsWebpackPlugin {
15
+ options: Options;
16
+ externalPlugin: ExternalsPlugin;
17
+ constructor(options: Pick<Options, 'map' | 'global'>);
18
+ apply(compiler: Compiler): void;
19
+ externalsPluginCallback(request: string | undefined, callback: (err?: undefined, result?: Global) => void): void;
20
+ exposeEntry(compiler: Compiler): void;
21
+ }
22
+
23
+ export { ExternalizeWordPressAssetsWebpackPlugin };
package/dist/index.d.ts CHANGED
@@ -1,26 +1,23 @@
1
1
  import { ExternalsPlugin, Compiler } from 'webpack';
2
2
 
3
- type ExternalsMap = {
4
- exact: Record<string, string>;
5
- startsWith: Record<string, string>;
6
- };
7
- type NormalizedOptions = {
8
- globalKey: string;
9
- externalsMap: ExternalsMap;
10
- };
3
+ type Global = string | string[];
4
+ type RequestToGlobalMap = Array<{
5
+ request: string | RegExp;
6
+ global: Global;
7
+ }>;
8
+
11
9
  type Options = {
12
- globalKey: string;
13
- externalsMap?: Partial<ExternalsMap>;
10
+ type: string;
11
+ global?: (entryName: string) => Global;
12
+ map: RequestToGlobalMap;
14
13
  };
15
14
  declare class ExternalizeWordPressAssetsWebpackPlugin {
15
+ options: Options;
16
16
  externalPlugin: ExternalsPlugin;
17
- options: NormalizedOptions;
18
- constructor(options: Options);
17
+ constructor(options: Pick<Options, 'map' | 'global'>);
19
18
  apply(compiler: Compiler): void;
20
- requestToExternal(request?: string): string | string[] | undefined;
21
- exportAsWindowItem(compiler: Compiler): void;
22
- kebabToCamelCase(kebabCase: string): string;
23
- normalizeOptions(options: Options): NormalizedOptions;
19
+ externalsPluginCallback(request: string | undefined, callback: (err?: undefined, result?: Global) => void): void;
20
+ exposeEntry(compiler: Compiler): void;
24
21
  }
25
22
 
26
23
  export { ExternalizeWordPressAssetsWebpackPlugin };
package/dist/index.js CHANGED
@@ -23,88 +23,87 @@ __export(src_exports, {
23
23
  ExternalizeWordPressAssetsWebpackPlugin: () => ExternalizeWordPressAssetsWebpackPlugin
24
24
  });
25
25
  module.exports = __toCommonJS(src_exports);
26
+
27
+ // src/plugin.ts
26
28
  var import_webpack = require("webpack");
27
- var baseExternalsMap = {
28
- exact: {
29
- react: "React",
30
- "react-dom": "ReactDOM"
31
- },
32
- startsWith: {
33
- "@elementor/": "__UNSTABLE__elementorPackages",
34
- "@wordpress/": "wp"
29
+
30
+ // src/utils.ts
31
+ function transformRequestToGlobal(request, map) {
32
+ if (!request) {
33
+ return null;
35
34
  }
36
- };
35
+ for (const item of map) {
36
+ let { request: requestRegex, global } = item;
37
+ if (!(requestRegex instanceof RegExp)) {
38
+ requestRegex = new RegExp(`^${requestRegex}$`);
39
+ }
40
+ const matches = request.match(requestRegex);
41
+ if (matches) {
42
+ return replaceGlobal(global, matches);
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+ function replaceGlobal(global, matches) {
48
+ let result = typeof global === "string" ? [global] : [...global];
49
+ matches.forEach((value, index) => {
50
+ result = result.map((item) => item.replace(`$${index}`, kebabToCamelCase(value)));
51
+ });
52
+ return result;
53
+ }
54
+ function kebabToCamelCase(kebabCase) {
55
+ return kebabCase.replace(
56
+ /-(\w)/g,
57
+ (_, w) => w.toUpperCase()
58
+ );
59
+ }
60
+
61
+ // src/plugin.ts
37
62
  var ExternalizeWordPressAssetsWebpackPlugin = class {
38
- externalPlugin;
39
63
  options;
64
+ externalPlugin;
40
65
  constructor(options) {
41
- this.options = this.normalizeOptions(options);
66
+ this.options = {
67
+ map: options.map,
68
+ global: options.global,
69
+ type: "window"
70
+ };
42
71
  this.externalPlugin = new import_webpack.ExternalsPlugin(
43
- "window",
44
- ({ request }, callback) => {
45
- const externalRequest = this.requestToExternal(request);
46
- if (externalRequest) {
47
- return callback(void 0, externalRequest);
48
- }
49
- return callback();
50
- }
72
+ this.options.type,
73
+ ({ request }, callback) => this.externalsPluginCallback(request, callback)
51
74
  );
52
75
  }
53
76
  apply(compiler) {
54
77
  this.externalPlugin.apply(compiler);
55
78
  compiler.hooks.environment.tap(this.constructor.name, () => {
56
- this.exportAsWindowItem(compiler);
79
+ this.exposeEntry(compiler);
57
80
  });
58
81
  }
59
- requestToExternal(request) {
60
- if (!request) {
82
+ externalsPluginCallback(request, callback) {
83
+ const global = transformRequestToGlobal(request, this.options.map);
84
+ if (!global) {
85
+ callback();
61
86
  return;
62
87
  }
63
- const { exact, startsWith } = this.options.externalsMap;
64
- if (Object.keys(exact).includes(request)) {
65
- return exact[request];
66
- }
67
- for (const [prefix, globalKey] of Object.entries(startsWith)) {
68
- if (request.startsWith(prefix)) {
69
- return [globalKey, this.kebabToCamelCase(request.replace(prefix, ""))];
70
- }
71
- }
72
- }
73
- exportAsWindowItem(compiler) {
74
- compiler.options.output.enabledLibraryTypes?.push("window");
75
- compiler.options.entry = Object.fromEntries(
76
- Object.entries(compiler.options.entry).map(([name, entry]) => [
77
- name,
78
- {
79
- ...entry,
80
- library: {
81
- name: [this.options.globalKey, this.kebabToCamelCase(name)],
82
- type: "window"
83
- }
84
- }
85
- ])
86
- );
88
+ callback(void 0, global);
87
89
  }
88
- kebabToCamelCase(kebabCase) {
89
- return kebabCase.replace(
90
- /-(\w)/g,
91
- (_, w) => w.toUpperCase()
92
- );
93
- }
94
- normalizeOptions(options) {
95
- return {
96
- ...options || {},
97
- externalsMap: {
98
- exact: {
99
- ...baseExternalsMap.exact,
100
- ...options?.externalsMap?.exact || {}
101
- },
102
- startsWith: {
103
- ...baseExternalsMap.startsWith,
104
- ...options?.externalsMap?.startsWith || {}
90
+ exposeEntry(compiler) {
91
+ compiler.options.output.enabledLibraryTypes?.push(this.options.type);
92
+ const transformEntryNameToGlobal = this.options.global;
93
+ const entry = compiler.options.entry;
94
+ if (!transformEntryNameToGlobal) {
95
+ return;
96
+ }
97
+ compiler.options.entry = Object.entries(entry).reduce((carry, [name, entryItem]) => ({
98
+ ...carry,
99
+ [name]: {
100
+ ...entryItem,
101
+ library: {
102
+ name: transformEntryNameToGlobal(kebabToCamelCase(name)),
103
+ type: this.options.type
105
104
  }
106
105
  }
107
- };
106
+ }), {});
108
107
  }
109
108
  };
110
109
  // Annotate the CommonJS export names for ESM import in node:
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { ExternalsPlugin, Compiler } from 'webpack';\n\ntype ExternalsMap = {\n\texact: Record<string, string>;\n\tstartsWith: Record<string, string>;\n};\n\ntype NormalizedOptions = {\n\tglobalKey: string,\n\texternalsMap: ExternalsMap\n};\n\ntype Options = {\n\tglobalKey: string,\n\texternalsMap?: Partial<ExternalsMap>\n};\n\nconst baseExternalsMap: ExternalsMap = {\n\texact: {\n\t\treact: 'React',\n\t\t'react-dom': 'ReactDOM',\n\t},\n\tstartsWith: {\n\t\t'@elementor/': '__UNSTABLE__elementorPackages',\n\t\t'@wordpress/': 'wp',\n\t},\n};\n\nexport class ExternalizeWordPressAssetsWebpackPlugin {\n\texternalPlugin: ExternalsPlugin;\n\n\toptions: NormalizedOptions;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = this.normalizeOptions( options );\n\n\t\tthis.externalPlugin = new ExternalsPlugin(\n\t\t\t'window',\n\t\t\t( { request }, callback ) => {\n\t\t\t\tconst externalRequest = this.requestToExternal( request );\n\n\t\t\t\tif ( externalRequest ) {\n\t\t\t\t\treturn callback( undefined, externalRequest );\n\t\t\t\t}\n\n\t\t\t\treturn callback();\n\t\t\t}\n\t\t);\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tthis.externalPlugin.apply( compiler );\n\n\t\tcompiler.hooks.environment.tap( this.constructor.name, () => {\n\t\t\tthis.exportAsWindowItem( compiler );\n\t\t} );\n\t}\n\n\trequestToExternal( request?: string ) {\n\t\tif ( ! request ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { exact, startsWith } = this.options.externalsMap;\n\n\t\tif ( Object.keys( exact ).includes( request ) ) {\n\t\t\treturn exact[ request ];\n\t\t}\n\n\t\tfor ( const [ prefix, globalKey ] of Object.entries( startsWith ) ) {\n\t\t\tif ( request.startsWith( prefix ) ) {\n\t\t\t\treturn [ globalKey, this.kebabToCamelCase( request.replace( prefix, '' ) ) ];\n\t\t\t}\n\t\t}\n\t}\n\n\texportAsWindowItem( compiler: Compiler ) {\n\t\tcompiler.options.output.enabledLibraryTypes?.push( 'window' );\n\n\t\tcompiler.options.entry = Object.fromEntries(\n\t\t\tObject.entries( compiler.options.entry ).map( ( [ name, entry ] ) => [\n\t\t\t\tname,\n\t\t\t\t{\n\t\t\t\t\t...entry,\n\t\t\t\t\tlibrary: {\n\t\t\t\t\t\tname: [ this.options.globalKey, this.kebabToCamelCase( name ) ],\n\t\t\t\t\t\ttype: 'window',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t] )\n\t\t);\n\t}\n\n\tkebabToCamelCase( kebabCase: string ) {\n\t\treturn kebabCase.replace(\n\t\t\t/-(\\w)/g,\n\t\t\t( _, w: string ) => w.toUpperCase()\n\t\t);\n\t}\n\n\tnormalizeOptions( options: Options ): NormalizedOptions {\n\t\treturn {\n\t\t\t...( options || {} ),\n\t\t\texternalsMap: {\n\t\t\t\texact: {\n\t\t\t\t\t...baseExternalsMap.exact,\n\t\t\t\t\t...( options?.externalsMap?.exact || {} ),\n\t\t\t\t},\n\t\t\t\tstartsWith: {\n\t\t\t\t\t...baseExternalsMap.startsWith,\n\t\t\t\t\t...( options?.externalsMap?.startsWith || {} ),\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0C;AAiB1C,IAAM,mBAAiC;AAAA,EACtC,OAAO;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACd;AAAA,EACA,YAAY;AAAA,IACX,eAAe;AAAA,IACf,eAAe;AAAA,EAChB;AACD;AAEO,IAAM,0CAAN,MAA8C;AAAA,EACpD;AAAA,EAEA;AAAA,EAEA,YAAa,SAAmB;AAC/B,SAAK,UAAU,KAAK,iBAAkB,OAAQ;AAE9C,SAAK,iBAAiB,IAAI;AAAA,MACzB;AAAA,MACA,CAAE,EAAE,QAAQ,GAAG,aAAc;AAC5B,cAAM,kBAAkB,KAAK,kBAAmB,OAAQ;AAExD,YAAK,iBAAkB;AACtB,iBAAO,SAAU,QAAW,eAAgB;AAAA,QAC7C;AAEA,eAAO,SAAS;AAAA,MACjB;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAO,UAAqB;AAC3B,SAAK,eAAe,MAAO,QAAS;AAEpC,aAAS,MAAM,YAAY,IAAK,KAAK,YAAY,MAAM,MAAM;AAC5D,WAAK,mBAAoB,QAAS;AAAA,IACnC,CAAE;AAAA,EACH;AAAA,EAEA,kBAAmB,SAAmB;AACrC,QAAK,CAAE,SAAU;AAChB;AAAA,IACD;AAEA,UAAM,EAAE,OAAO,WAAW,IAAI,KAAK,QAAQ;AAE3C,QAAK,OAAO,KAAM,KAAM,EAAE,SAAU,OAAQ,GAAI;AAC/C,aAAO,MAAO,OAAQ;AAAA,IACvB;AAEA,eAAY,CAAE,QAAQ,SAAU,KAAK,OAAO,QAAS,UAAW,GAAI;AACnE,UAAK,QAAQ,WAAY,MAAO,GAAI;AACnC,eAAO,CAAE,WAAW,KAAK,iBAAkB,QAAQ,QAAS,QAAQ,EAAG,CAAE,CAAE;AAAA,MAC5E;AAAA,IACD;AAAA,EACD;AAAA,EAEA,mBAAoB,UAAqB;AACxC,aAAS,QAAQ,OAAO,qBAAqB,KAAM,QAAS;AAE5D,aAAS,QAAQ,QAAQ,OAAO;AAAA,MAC/B,OAAO,QAAS,SAAS,QAAQ,KAAM,EAAE,IAAK,CAAE,CAAE,MAAM,KAAM,MAAO;AAAA,QACpE;AAAA,QACA;AAAA,UACC,GAAG;AAAA,UACH,SAAS;AAAA,YACR,MAAM,CAAE,KAAK,QAAQ,WAAW,KAAK,iBAAkB,IAAK,CAAE;AAAA,YAC9D,MAAM;AAAA,UACP;AAAA,QACD;AAAA,MACD,CAAE;AAAA,IACH;AAAA,EACD;AAAA,EAEA,iBAAkB,WAAoB;AACrC,WAAO,UAAU;AAAA,MAChB;AAAA,MACA,CAAE,GAAG,MAAe,EAAE,YAAY;AAAA,IACnC;AAAA,EACD;AAAA,EAEA,iBAAkB,SAAsC;AACvD,WAAO;AAAA,MACN,GAAK,WAAW,CAAC;AAAA,MACjB,cAAc;AAAA,QACb,OAAO;AAAA,UACN,GAAG,iBAAiB;AAAA,UACpB,GAAK,SAAS,cAAc,SAAS,CAAC;AAAA,QACvC;AAAA,QACA,YAAY;AAAA,UACX,GAAG,iBAAiB;AAAA,UACpB,GAAK,SAAS,cAAc,cAAc,CAAC;AAAA,QAC5C;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/utils.ts"],"sourcesContent":["export { default as ExternalizeWordPressAssetsWebpackPlugin } from './plugin';\n","import { ExternalsPlugin, Compiler } from 'webpack';\nimport { kebabToCamelCase, transformRequestToGlobal } from './utils';\nimport { RequestToGlobalMap, Global } from './types';\n\ntype Options = {\n\ttype: string,\n\tglobal?: ( entryName: string ) => Global,\n\tmap: RequestToGlobalMap\n};\n\nexport default class ExternalizeWordPressAssetsWebpackPlugin {\n\toptions: Options;\n\n\texternalPlugin: ExternalsPlugin;\n\n\tconstructor( options: Pick<Options, 'map' | 'global'> ) {\n\t\tthis.options = {\n\t\t\tmap: options.map,\n\t\t\tglobal: options.global,\n\t\t\ttype: 'window',\n\t\t};\n\n\t\tthis.externalPlugin = new ExternalsPlugin(\n\t\t\tthis.options.type,\n\t\t\t( { request }, callback ) => this.externalsPluginCallback( request, callback )\n\t\t);\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tthis.externalPlugin.apply( compiler );\n\n\t\tcompiler.hooks.environment.tap( this.constructor.name, () => {\n\t\t\tthis.exposeEntry( compiler );\n\t\t} );\n\t}\n\n\texternalsPluginCallback(\n\t\trequest: string | undefined,\n\t\tcallback: ( err?: undefined, result?: Global ) => void\n\t) {\n\t\tconst global = transformRequestToGlobal( request, this.options.map );\n\n\t\tif ( ! global ) {\n\t\t\tcallback();\n\n\t\t\treturn;\n\t\t}\n\n\t\tcallback( undefined, global );\n\t}\n\n\texposeEntry( compiler: Compiler ) {\n\t\tcompiler.options.output.enabledLibraryTypes?.push( this.options.type );\n\n\t\tconst transformEntryNameToGlobal = this.options.global;\n\t\tconst entry = compiler.options.entry;\n\n\t\tif ( ! transformEntryNameToGlobal ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcompiler.options.entry = Object.entries( entry )\n\t\t\t.reduce( ( carry, [ name, entryItem ] ) => ( {\n\t\t\t\t...carry,\n\t\t\t\t[ name ]: {\n\t\t\t\t\t...entryItem,\n\t\t\t\t\tlibrary: {\n\t\t\t\t\t\tname: transformEntryNameToGlobal( kebabToCamelCase( name ) ),\n\t\t\t\t\t\ttype: this.options.type,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t} ), {} );\n\t}\n}\n","import { RequestToGlobalMap } from './types';\n\nexport function transformRequestToGlobal( request: string | undefined, map: RequestToGlobalMap ) {\n\tif ( ! request ) {\n\t\treturn null;\n\t}\n\n\tfor ( const item of map ) {\n\t\tlet { request: requestRegex, global } = item;\n\n\t\tif ( ! ( requestRegex instanceof RegExp ) ) {\n\t\t\trequestRegex = new RegExp( `^${ requestRegex }$` );\n\t\t}\n\n\t\tconst matches = request.match( requestRegex );\n\n\t\tif ( matches ) {\n\t\t\treturn replaceGlobal( global, matches );\n\t\t}\n\t}\n\n\treturn null;\n}\n\nexport function replaceGlobal( global: string | string[], matches: RegExpMatchArray ) {\n\tlet result = typeof global === 'string' ? [ global ] : [ ...global ];\n\n\tmatches.forEach( ( value, index ) => {\n\t\t// Replace regex backreferences with capture groups.\n\t\t// The user can set ['something', '$1', 'a', '$2'] in the global, and the backreferences will\n\t\t// be replaced by the matched groups in the regex.\n\t\tresult = result.map( ( item ) => item.replace( `$${ index }`, kebabToCamelCase( value ) ) );\n\t} );\n\n\treturn result;\n}\n\nexport function kebabToCamelCase( kebabCase: string ) {\n\treturn kebabCase.replace(\n\t\t/-(\\w)/g,\n\t\t( _, w: string ) => w.toUpperCase()\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAA0C;;;ACEnC,SAAS,yBAA0B,SAA6B,KAA0B;AAChG,MAAK,CAAE,SAAU;AAChB,WAAO;AAAA,EACR;AAEA,aAAY,QAAQ,KAAM;AACzB,QAAI,EAAE,SAAS,cAAc,OAAO,IAAI;AAExC,QAAK,EAAI,wBAAwB,SAAW;AAC3C,qBAAe,IAAI,OAAQ,IAAK,YAAa,GAAI;AAAA,IAClD;AAEA,UAAM,UAAU,QAAQ,MAAO,YAAa;AAE5C,QAAK,SAAU;AACd,aAAO,cAAe,QAAQ,OAAQ;AAAA,IACvC;AAAA,EACD;AAEA,SAAO;AACR;AAEO,SAAS,cAAe,QAA2B,SAA4B;AACrF,MAAI,SAAS,OAAO,WAAW,WAAW,CAAE,MAAO,IAAI,CAAE,GAAG,MAAO;AAEnE,UAAQ,QAAS,CAAE,OAAO,UAAW;AAIpC,aAAS,OAAO,IAAK,CAAE,SAAU,KAAK,QAAS,IAAK,KAAM,IAAI,iBAAkB,KAAM,CAAE,CAAE;AAAA,EAC3F,CAAE;AAEF,SAAO;AACR;AAEO,SAAS,iBAAkB,WAAoB;AACrD,SAAO,UAAU;AAAA,IAChB;AAAA,IACA,CAAE,GAAG,MAAe,EAAE,YAAY;AAAA,EACnC;AACD;;;ADhCA,IAAqB,0CAArB,MAA6D;AAAA,EAC5D;AAAA,EAEA;AAAA,EAEA,YAAa,SAA2C;AACvD,SAAK,UAAU;AAAA,MACd,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,MAAM;AAAA,IACP;AAEA,SAAK,iBAAiB,IAAI;AAAA,MACzB,KAAK,QAAQ;AAAA,MACb,CAAE,EAAE,QAAQ,GAAG,aAAc,KAAK,wBAAyB,SAAS,QAAS;AAAA,IAC9E;AAAA,EACD;AAAA,EAEA,MAAO,UAAqB;AAC3B,SAAK,eAAe,MAAO,QAAS;AAEpC,aAAS,MAAM,YAAY,IAAK,KAAK,YAAY,MAAM,MAAM;AAC5D,WAAK,YAAa,QAAS;AAAA,IAC5B,CAAE;AAAA,EACH;AAAA,EAEA,wBACC,SACA,UACC;AACD,UAAM,SAAS,yBAA0B,SAAS,KAAK,QAAQ,GAAI;AAEnE,QAAK,CAAE,QAAS;AACf,eAAS;AAET;AAAA,IACD;AAEA,aAAU,QAAW,MAAO;AAAA,EAC7B;AAAA,EAEA,YAAa,UAAqB;AACjC,aAAS,QAAQ,OAAO,qBAAqB,KAAM,KAAK,QAAQ,IAAK;AAErE,UAAM,6BAA6B,KAAK,QAAQ;AAChD,UAAM,QAAQ,SAAS,QAAQ;AAE/B,QAAK,CAAE,4BAA6B;AACnC;AAAA,IACD;AAEA,aAAS,QAAQ,QAAQ,OAAO,QAAS,KAAM,EAC7C,OAAQ,CAAE,OAAO,CAAE,MAAM,SAAU,OAAS;AAAA,MAC5C,GAAG;AAAA,MACH,CAAE,IAAK,GAAG;AAAA,QACT,GAAG;AAAA,QACH,SAAS;AAAA,UACR,MAAM,2BAA4B,iBAAkB,IAAK,CAAE;AAAA,UAC3D,MAAM,KAAK,QAAQ;AAAA,QACpB;AAAA,MACD;AAAA,IACD,IAAK,CAAC,CAAE;AAAA,EACV;AACD;","names":[]}
package/dist/index.mjs CHANGED
@@ -1,86 +1,83 @@
1
- // src/index.ts
1
+ // src/plugin.ts
2
2
  import { ExternalsPlugin } from "webpack";
3
- var baseExternalsMap = {
4
- exact: {
5
- react: "React",
6
- "react-dom": "ReactDOM"
7
- },
8
- startsWith: {
9
- "@elementor/": "__UNSTABLE__elementorPackages",
10
- "@wordpress/": "wp"
3
+
4
+ // src/utils.ts
5
+ function transformRequestToGlobal(request, map) {
6
+ if (!request) {
7
+ return null;
11
8
  }
12
- };
9
+ for (const item of map) {
10
+ let { request: requestRegex, global } = item;
11
+ if (!(requestRegex instanceof RegExp)) {
12
+ requestRegex = new RegExp(`^${requestRegex}$`);
13
+ }
14
+ const matches = request.match(requestRegex);
15
+ if (matches) {
16
+ return replaceGlobal(global, matches);
17
+ }
18
+ }
19
+ return null;
20
+ }
21
+ function replaceGlobal(global, matches) {
22
+ let result = typeof global === "string" ? [global] : [...global];
23
+ matches.forEach((value, index) => {
24
+ result = result.map((item) => item.replace(`$${index}`, kebabToCamelCase(value)));
25
+ });
26
+ return result;
27
+ }
28
+ function kebabToCamelCase(kebabCase) {
29
+ return kebabCase.replace(
30
+ /-(\w)/g,
31
+ (_, w) => w.toUpperCase()
32
+ );
33
+ }
34
+
35
+ // src/plugin.ts
13
36
  var ExternalizeWordPressAssetsWebpackPlugin = class {
14
- externalPlugin;
15
37
  options;
38
+ externalPlugin;
16
39
  constructor(options) {
17
- this.options = this.normalizeOptions(options);
40
+ this.options = {
41
+ map: options.map,
42
+ global: options.global,
43
+ type: "window"
44
+ };
18
45
  this.externalPlugin = new ExternalsPlugin(
19
- "window",
20
- ({ request }, callback) => {
21
- const externalRequest = this.requestToExternal(request);
22
- if (externalRequest) {
23
- return callback(void 0, externalRequest);
24
- }
25
- return callback();
26
- }
46
+ this.options.type,
47
+ ({ request }, callback) => this.externalsPluginCallback(request, callback)
27
48
  );
28
49
  }
29
50
  apply(compiler) {
30
51
  this.externalPlugin.apply(compiler);
31
52
  compiler.hooks.environment.tap(this.constructor.name, () => {
32
- this.exportAsWindowItem(compiler);
53
+ this.exposeEntry(compiler);
33
54
  });
34
55
  }
35
- requestToExternal(request) {
36
- if (!request) {
56
+ externalsPluginCallback(request, callback) {
57
+ const global = transformRequestToGlobal(request, this.options.map);
58
+ if (!global) {
59
+ callback();
37
60
  return;
38
61
  }
39
- const { exact, startsWith } = this.options.externalsMap;
40
- if (Object.keys(exact).includes(request)) {
41
- return exact[request];
42
- }
43
- for (const [prefix, globalKey] of Object.entries(startsWith)) {
44
- if (request.startsWith(prefix)) {
45
- return [globalKey, this.kebabToCamelCase(request.replace(prefix, ""))];
46
- }
47
- }
48
- }
49
- exportAsWindowItem(compiler) {
50
- compiler.options.output.enabledLibraryTypes?.push("window");
51
- compiler.options.entry = Object.fromEntries(
52
- Object.entries(compiler.options.entry).map(([name, entry]) => [
53
- name,
54
- {
55
- ...entry,
56
- library: {
57
- name: [this.options.globalKey, this.kebabToCamelCase(name)],
58
- type: "window"
59
- }
60
- }
61
- ])
62
- );
62
+ callback(void 0, global);
63
63
  }
64
- kebabToCamelCase(kebabCase) {
65
- return kebabCase.replace(
66
- /-(\w)/g,
67
- (_, w) => w.toUpperCase()
68
- );
69
- }
70
- normalizeOptions(options) {
71
- return {
72
- ...options || {},
73
- externalsMap: {
74
- exact: {
75
- ...baseExternalsMap.exact,
76
- ...options?.externalsMap?.exact || {}
77
- },
78
- startsWith: {
79
- ...baseExternalsMap.startsWith,
80
- ...options?.externalsMap?.startsWith || {}
64
+ exposeEntry(compiler) {
65
+ compiler.options.output.enabledLibraryTypes?.push(this.options.type);
66
+ const transformEntryNameToGlobal = this.options.global;
67
+ const entry = compiler.options.entry;
68
+ if (!transformEntryNameToGlobal) {
69
+ return;
70
+ }
71
+ compiler.options.entry = Object.entries(entry).reduce((carry, [name, entryItem]) => ({
72
+ ...carry,
73
+ [name]: {
74
+ ...entryItem,
75
+ library: {
76
+ name: transformEntryNameToGlobal(kebabToCamelCase(name)),
77
+ type: this.options.type
81
78
  }
82
79
  }
83
- };
80
+ }), {});
84
81
  }
85
82
  };
86
83
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { ExternalsPlugin, Compiler } from 'webpack';\n\ntype ExternalsMap = {\n\texact: Record<string, string>;\n\tstartsWith: Record<string, string>;\n};\n\ntype NormalizedOptions = {\n\tglobalKey: string,\n\texternalsMap: ExternalsMap\n};\n\ntype Options = {\n\tglobalKey: string,\n\texternalsMap?: Partial<ExternalsMap>\n};\n\nconst baseExternalsMap: ExternalsMap = {\n\texact: {\n\t\treact: 'React',\n\t\t'react-dom': 'ReactDOM',\n\t},\n\tstartsWith: {\n\t\t'@elementor/': '__UNSTABLE__elementorPackages',\n\t\t'@wordpress/': 'wp',\n\t},\n};\n\nexport class ExternalizeWordPressAssetsWebpackPlugin {\n\texternalPlugin: ExternalsPlugin;\n\n\toptions: NormalizedOptions;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = this.normalizeOptions( options );\n\n\t\tthis.externalPlugin = new ExternalsPlugin(\n\t\t\t'window',\n\t\t\t( { request }, callback ) => {\n\t\t\t\tconst externalRequest = this.requestToExternal( request );\n\n\t\t\t\tif ( externalRequest ) {\n\t\t\t\t\treturn callback( undefined, externalRequest );\n\t\t\t\t}\n\n\t\t\t\treturn callback();\n\t\t\t}\n\t\t);\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tthis.externalPlugin.apply( compiler );\n\n\t\tcompiler.hooks.environment.tap( this.constructor.name, () => {\n\t\t\tthis.exportAsWindowItem( compiler );\n\t\t} );\n\t}\n\n\trequestToExternal( request?: string ) {\n\t\tif ( ! request ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { exact, startsWith } = this.options.externalsMap;\n\n\t\tif ( Object.keys( exact ).includes( request ) ) {\n\t\t\treturn exact[ request ];\n\t\t}\n\n\t\tfor ( const [ prefix, globalKey ] of Object.entries( startsWith ) ) {\n\t\t\tif ( request.startsWith( prefix ) ) {\n\t\t\t\treturn [ globalKey, this.kebabToCamelCase( request.replace( prefix, '' ) ) ];\n\t\t\t}\n\t\t}\n\t}\n\n\texportAsWindowItem( compiler: Compiler ) {\n\t\tcompiler.options.output.enabledLibraryTypes?.push( 'window' );\n\n\t\tcompiler.options.entry = Object.fromEntries(\n\t\t\tObject.entries( compiler.options.entry ).map( ( [ name, entry ] ) => [\n\t\t\t\tname,\n\t\t\t\t{\n\t\t\t\t\t...entry,\n\t\t\t\t\tlibrary: {\n\t\t\t\t\t\tname: [ this.options.globalKey, this.kebabToCamelCase( name ) ],\n\t\t\t\t\t\ttype: 'window',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t] )\n\t\t);\n\t}\n\n\tkebabToCamelCase( kebabCase: string ) {\n\t\treturn kebabCase.replace(\n\t\t\t/-(\\w)/g,\n\t\t\t( _, w: string ) => w.toUpperCase()\n\t\t);\n\t}\n\n\tnormalizeOptions( options: Options ): NormalizedOptions {\n\t\treturn {\n\t\t\t...( options || {} ),\n\t\t\texternalsMap: {\n\t\t\t\texact: {\n\t\t\t\t\t...baseExternalsMap.exact,\n\t\t\t\t\t...( options?.externalsMap?.exact || {} ),\n\t\t\t\t},\n\t\t\t\tstartsWith: {\n\t\t\t\t\t...baseExternalsMap.startsWith,\n\t\t\t\t\t...( options?.externalsMap?.startsWith || {} ),\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n}\n"],"mappings":";AAAA,SAAS,uBAAiC;AAiB1C,IAAM,mBAAiC;AAAA,EACtC,OAAO;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACd;AAAA,EACA,YAAY;AAAA,IACX,eAAe;AAAA,IACf,eAAe;AAAA,EAChB;AACD;AAEO,IAAM,0CAAN,MAA8C;AAAA,EACpD;AAAA,EAEA;AAAA,EAEA,YAAa,SAAmB;AAC/B,SAAK,UAAU,KAAK,iBAAkB,OAAQ;AAE9C,SAAK,iBAAiB,IAAI;AAAA,MACzB;AAAA,MACA,CAAE,EAAE,QAAQ,GAAG,aAAc;AAC5B,cAAM,kBAAkB,KAAK,kBAAmB,OAAQ;AAExD,YAAK,iBAAkB;AACtB,iBAAO,SAAU,QAAW,eAAgB;AAAA,QAC7C;AAEA,eAAO,SAAS;AAAA,MACjB;AAAA,IACD;AAAA,EACD;AAAA,EAEA,MAAO,UAAqB;AAC3B,SAAK,eAAe,MAAO,QAAS;AAEpC,aAAS,MAAM,YAAY,IAAK,KAAK,YAAY,MAAM,MAAM;AAC5D,WAAK,mBAAoB,QAAS;AAAA,IACnC,CAAE;AAAA,EACH;AAAA,EAEA,kBAAmB,SAAmB;AACrC,QAAK,CAAE,SAAU;AAChB;AAAA,IACD;AAEA,UAAM,EAAE,OAAO,WAAW,IAAI,KAAK,QAAQ;AAE3C,QAAK,OAAO,KAAM,KAAM,EAAE,SAAU,OAAQ,GAAI;AAC/C,aAAO,MAAO,OAAQ;AAAA,IACvB;AAEA,eAAY,CAAE,QAAQ,SAAU,KAAK,OAAO,QAAS,UAAW,GAAI;AACnE,UAAK,QAAQ,WAAY,MAAO,GAAI;AACnC,eAAO,CAAE,WAAW,KAAK,iBAAkB,QAAQ,QAAS,QAAQ,EAAG,CAAE,CAAE;AAAA,MAC5E;AAAA,IACD;AAAA,EACD;AAAA,EAEA,mBAAoB,UAAqB;AACxC,aAAS,QAAQ,OAAO,qBAAqB,KAAM,QAAS;AAE5D,aAAS,QAAQ,QAAQ,OAAO;AAAA,MAC/B,OAAO,QAAS,SAAS,QAAQ,KAAM,EAAE,IAAK,CAAE,CAAE,MAAM,KAAM,MAAO;AAAA,QACpE;AAAA,QACA;AAAA,UACC,GAAG;AAAA,UACH,SAAS;AAAA,YACR,MAAM,CAAE,KAAK,QAAQ,WAAW,KAAK,iBAAkB,IAAK,CAAE;AAAA,YAC9D,MAAM;AAAA,UACP;AAAA,QACD;AAAA,MACD,CAAE;AAAA,IACH;AAAA,EACD;AAAA,EAEA,iBAAkB,WAAoB;AACrC,WAAO,UAAU;AAAA,MAChB;AAAA,MACA,CAAE,GAAG,MAAe,EAAE,YAAY;AAAA,IACnC;AAAA,EACD;AAAA,EAEA,iBAAkB,SAAsC;AACvD,WAAO;AAAA,MACN,GAAK,WAAW,CAAC;AAAA,MACjB,cAAc;AAAA,QACb,OAAO;AAAA,UACN,GAAG,iBAAiB;AAAA,UACpB,GAAK,SAAS,cAAc,SAAS,CAAC;AAAA,QACvC;AAAA,QACA,YAAY;AAAA,UACX,GAAG,iBAAiB;AAAA,UACpB,GAAK,SAAS,cAAc,cAAc,CAAC;AAAA,QAC5C;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/utils.ts"],"sourcesContent":["import { ExternalsPlugin, Compiler } from 'webpack';\nimport { kebabToCamelCase, transformRequestToGlobal } from './utils';\nimport { RequestToGlobalMap, Global } from './types';\n\ntype Options = {\n\ttype: string,\n\tglobal?: ( entryName: string ) => Global,\n\tmap: RequestToGlobalMap\n};\n\nexport default class ExternalizeWordPressAssetsWebpackPlugin {\n\toptions: Options;\n\n\texternalPlugin: ExternalsPlugin;\n\n\tconstructor( options: Pick<Options, 'map' | 'global'> ) {\n\t\tthis.options = {\n\t\t\tmap: options.map,\n\t\t\tglobal: options.global,\n\t\t\ttype: 'window',\n\t\t};\n\n\t\tthis.externalPlugin = new ExternalsPlugin(\n\t\t\tthis.options.type,\n\t\t\t( { request }, callback ) => this.externalsPluginCallback( request, callback )\n\t\t);\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tthis.externalPlugin.apply( compiler );\n\n\t\tcompiler.hooks.environment.tap( this.constructor.name, () => {\n\t\t\tthis.exposeEntry( compiler );\n\t\t} );\n\t}\n\n\texternalsPluginCallback(\n\t\trequest: string | undefined,\n\t\tcallback: ( err?: undefined, result?: Global ) => void\n\t) {\n\t\tconst global = transformRequestToGlobal( request, this.options.map );\n\n\t\tif ( ! global ) {\n\t\t\tcallback();\n\n\t\t\treturn;\n\t\t}\n\n\t\tcallback( undefined, global );\n\t}\n\n\texposeEntry( compiler: Compiler ) {\n\t\tcompiler.options.output.enabledLibraryTypes?.push( this.options.type );\n\n\t\tconst transformEntryNameToGlobal = this.options.global;\n\t\tconst entry = compiler.options.entry;\n\n\t\tif ( ! transformEntryNameToGlobal ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcompiler.options.entry = Object.entries( entry )\n\t\t\t.reduce( ( carry, [ name, entryItem ] ) => ( {\n\t\t\t\t...carry,\n\t\t\t\t[ name ]: {\n\t\t\t\t\t...entryItem,\n\t\t\t\t\tlibrary: {\n\t\t\t\t\t\tname: transformEntryNameToGlobal( kebabToCamelCase( name ) ),\n\t\t\t\t\t\ttype: this.options.type,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t} ), {} );\n\t}\n}\n","import { RequestToGlobalMap } from './types';\n\nexport function transformRequestToGlobal( request: string | undefined, map: RequestToGlobalMap ) {\n\tif ( ! request ) {\n\t\treturn null;\n\t}\n\n\tfor ( const item of map ) {\n\t\tlet { request: requestRegex, global } = item;\n\n\t\tif ( ! ( requestRegex instanceof RegExp ) ) {\n\t\t\trequestRegex = new RegExp( `^${ requestRegex }$` );\n\t\t}\n\n\t\tconst matches = request.match( requestRegex );\n\n\t\tif ( matches ) {\n\t\t\treturn replaceGlobal( global, matches );\n\t\t}\n\t}\n\n\treturn null;\n}\n\nexport function replaceGlobal( global: string | string[], matches: RegExpMatchArray ) {\n\tlet result = typeof global === 'string' ? [ global ] : [ ...global ];\n\n\tmatches.forEach( ( value, index ) => {\n\t\t// Replace regex backreferences with capture groups.\n\t\t// The user can set ['something', '$1', 'a', '$2'] in the global, and the backreferences will\n\t\t// be replaced by the matched groups in the regex.\n\t\tresult = result.map( ( item ) => item.replace( `$${ index }`, kebabToCamelCase( value ) ) );\n\t} );\n\n\treturn result;\n}\n\nexport function kebabToCamelCase( kebabCase: string ) {\n\treturn kebabCase.replace(\n\t\t/-(\\w)/g,\n\t\t( _, w: string ) => w.toUpperCase()\n\t);\n}\n"],"mappings":";AAAA,SAAS,uBAAiC;;;ACEnC,SAAS,yBAA0B,SAA6B,KAA0B;AAChG,MAAK,CAAE,SAAU;AAChB,WAAO;AAAA,EACR;AAEA,aAAY,QAAQ,KAAM;AACzB,QAAI,EAAE,SAAS,cAAc,OAAO,IAAI;AAExC,QAAK,EAAI,wBAAwB,SAAW;AAC3C,qBAAe,IAAI,OAAQ,IAAK,YAAa,GAAI;AAAA,IAClD;AAEA,UAAM,UAAU,QAAQ,MAAO,YAAa;AAE5C,QAAK,SAAU;AACd,aAAO,cAAe,QAAQ,OAAQ;AAAA,IACvC;AAAA,EACD;AAEA,SAAO;AACR;AAEO,SAAS,cAAe,QAA2B,SAA4B;AACrF,MAAI,SAAS,OAAO,WAAW,WAAW,CAAE,MAAO,IAAI,CAAE,GAAG,MAAO;AAEnE,UAAQ,QAAS,CAAE,OAAO,UAAW;AAIpC,aAAS,OAAO,IAAK,CAAE,SAAU,KAAK,QAAS,IAAK,KAAM,IAAI,iBAAkB,KAAM,CAAE,CAAE;AAAA,EAC3F,CAAE;AAEF,SAAO;AACR;AAEO,SAAS,iBAAkB,WAAoB;AACrD,SAAO,UAAU;AAAA,IAChB;AAAA,IACA,CAAE,GAAG,MAAe,EAAE,YAAY;AAAA,EACnC;AACD;;;ADhCA,IAAqB,0CAArB,MAA6D;AAAA,EAC5D;AAAA,EAEA;AAAA,EAEA,YAAa,SAA2C;AACvD,SAAK,UAAU;AAAA,MACd,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,MAAM;AAAA,IACP;AAEA,SAAK,iBAAiB,IAAI;AAAA,MACzB,KAAK,QAAQ;AAAA,MACb,CAAE,EAAE,QAAQ,GAAG,aAAc,KAAK,wBAAyB,SAAS,QAAS;AAAA,IAC9E;AAAA,EACD;AAAA,EAEA,MAAO,UAAqB;AAC3B,SAAK,eAAe,MAAO,QAAS;AAEpC,aAAS,MAAM,YAAY,IAAK,KAAK,YAAY,MAAM,MAAM;AAC5D,WAAK,YAAa,QAAS;AAAA,IAC5B,CAAE;AAAA,EACH;AAAA,EAEA,wBACC,SACA,UACC;AACD,UAAM,SAAS,yBAA0B,SAAS,KAAK,QAAQ,GAAI;AAEnE,QAAK,CAAE,QAAS;AACf,eAAS;AAET;AAAA,IACD;AAEA,aAAU,QAAW,MAAO;AAAA,EAC7B;AAAA,EAEA,YAAa,UAAqB;AACjC,aAAS,QAAQ,OAAO,qBAAqB,KAAM,KAAK,QAAQ,IAAK;AAErE,UAAM,6BAA6B,KAAK,QAAQ;AAChD,UAAM,QAAQ,SAAS,QAAQ;AAE/B,QAAK,CAAE,4BAA6B;AACnC;AAAA,IACD;AAEA,aAAS,QAAQ,QAAQ,OAAO,QAAS,KAAM,EAC7C,OAAQ,CAAE,OAAO,CAAE,MAAM,SAAU,OAAS;AAAA,MAC5C,GAAG;AAAA,MACH,CAAE,IAAK,GAAG;AAAA,QACT,GAAG;AAAA,QACH,SAAS;AAAA,UACR,MAAM,2BAA4B,iBAAkB,IAAK,CAAE;AAAA,UAC3D,MAAM,KAAK,QAAQ;AAAA,QACpB;AAAA,MACD;AAAA,IACD,IAAK,CAAC,CAAE;AAAA,EACV;AACD;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/externalize-wordpress-assets-webpack-plugin",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -19,7 +19,7 @@
19
19
  "repository": {
20
20
  "type": "git",
21
21
  "url": "https://github.com/elementor/elementor-packages.git",
22
- "directory": "packages/libs/externalize-wordpress-assets-webpack-plugin"
22
+ "directory": "packages/tools/externalize-wordpress-assets-webpack-plugin"
23
23
  },
24
24
  "bugs": {
25
25
  "url": "https://github.com/elementor/elementor-packages/issues"
@@ -34,5 +34,5 @@
34
34
  "peerDependencies": {
35
35
  "webpack": "5.x"
36
36
  },
37
- "gitHead": "f93a1ed5350b151f17d65b21b0b43398774dccc5"
37
+ "gitHead": "7fd9a516887f8bdb3479c54a48dafcb12bb41db7"
38
38
  }
@@ -2,15 +2,7 @@
2
2
 
3
3
  exports[`@elementor/externalize-wordpress-assets-webpack-plugin should externalize Elementor & WordPress assets 1`] = `
4
4
  ""use strict";
5
- /*
6
- * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
7
- * This devtool is neither made for production nor for readable output files.
8
- * It uses "eval()" calls to create a separate source file in the browser devtools.
9
- * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
10
- * or disable the default devtool with "devtool: false".
11
- * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
12
- */
13
- (self["webpackChunk"] = self["webpackChunk"] || []).push([["app"],{
5
+ (self["webpackChunk"] = self["webpackChunk"] || []).push([["my-app-test"],{
14
6
 
15
7
  /***/ "./.":
16
8
  /*!***********!*\\
@@ -18,14 +10,46 @@ exports[`@elementor/externalize-wordpress-assets-webpack-plugin should externali
18
10
  \\***********/
19
11
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
20
12
 
21
- eval("__webpack_require__.r(__webpack_exports__);\\n/* harmony import */ var _elementor_editor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/editor */ \\"@elementor/editor\\");\\n/* harmony import */ var _elementor_editor__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor__WEBPACK_IMPORTED_MODULE_0__);\\n/* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/element */ \\"@wordpress/element\\");\\n/* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_1__);\\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react */ \\"react\\");\\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__);\\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-dom */ \\"react-dom\\");\\n/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_3__);\\n/* harmony import */ var _other_package_name__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @other/package-name */ \\"@other/package-name\\");\\n/* harmony import */ var _other_package_name__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_other_package_name__WEBPACK_IMPORTED_MODULE_4__);\\n\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\n\\t\\t\\t_elementor_editor__WEBPACK_IMPORTED_MODULE_0___default()();\\n\\t\\t\\t_wordpress_element__WEBPACK_IMPORTED_MODULE_1___default()();\\n\\t\\t\\treact__WEBPACK_IMPORTED_MODULE_2___default()();\\n\\t\\t\\treact_dom__WEBPACK_IMPORTED_MODULE_3___default()();\\n\\t\\t\\t_other_package_name__WEBPACK_IMPORTED_MODULE_4___default()();\\n\\t\\t\\n\\n//# sourceURL=webpack:///./.?");
13
+ __webpack_require__.r(__webpack_exports__);
14
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
15
+ /* harmony export */ test: () => (/* binding */ test)
16
+ /* harmony export */ });
17
+ /* harmony import */ var _elementor_editor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @elementor/editor */ "@elementor/editor");
18
+ /* harmony import */ var _elementor_editor__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor__WEBPACK_IMPORTED_MODULE_0__);
19
+ /* harmony import */ var _elementor_editor_panels__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @elementor/editor-panels */ "@elementor/editor-panels");
20
+ /* harmony import */ var _elementor_editor_panels__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_elementor_editor_panels__WEBPACK_IMPORTED_MODULE_1__);
21
+ /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element");
22
+ /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_2__);
23
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react */ "react");
24
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
25
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react-dom */ "react-dom");
26
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_4__);
27
+ /* harmony import */ var _other_package_name__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @other/package-name */ "@other/package-name");
28
+ /* harmony import */ var _other_package_name__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_other_package_name__WEBPACK_IMPORTED_MODULE_5__);
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+ _elementor_editor__WEBPACK_IMPORTED_MODULE_0___default()();
38
+ _elementor_editor_panels__WEBPACK_IMPORTED_MODULE_1___default()();
39
+ _wordpress_element__WEBPACK_IMPORTED_MODULE_2___default()();
40
+ react__WEBPACK_IMPORTED_MODULE_3___default()();
41
+ react_dom__WEBPACK_IMPORTED_MODULE_4___default()();
42
+ _other_package_name__WEBPACK_IMPORTED_MODULE_5___default()();
43
+
44
+ const test = 'This is test for exporting something';
45
+
22
46
 
23
47
  /***/ }),
24
48
 
25
49
  /***/ "react":
26
- /*!************************!*\\
27
- !*** external "React" ***!
28
- \\************************/
50
+ /*!**************************!*\\
51
+ !*** external ["React"] ***!
52
+ \\**************************/
29
53
  /***/ ((module) => {
30
54
 
31
55
  module.exports = window["React"];
@@ -33,32 +57,42 @@ module.exports = window["React"];
33
57
  /***/ }),
34
58
 
35
59
  /***/ "react-dom":
36
- /*!***************************!*\\
37
- !*** external "ReactDOM" ***!
38
- \\***************************/
60
+ /*!*****************************!*\\
61
+ !*** external ["ReactDOM"] ***!
62
+ \\*****************************/
39
63
  /***/ ((module) => {
40
64
 
41
65
  module.exports = window["ReactDOM"];
42
66
 
43
67
  /***/ }),
44
68
 
45
- /***/ "@other/package-name":
46
- /*!***********************************!*\\
47
- !*** external "otherPackageName" ***!
48
- \\***********************************/
69
+ /***/ "@elementor/editor":
70
+ /*!***********************************************!*\\
71
+ !*** external ["elementorPackages","editor"] ***!
72
+ \\***********************************************/
49
73
  /***/ ((module) => {
50
74
 
51
- module.exports = window["otherPackageName"];
75
+ module.exports = window["elementorPackages"]["editor"];
52
76
 
53
77
  /***/ }),
54
78
 
55
- /***/ "@elementor/editor":
56
- /*!***********************************************************!*\\
57
- !*** external ["__UNSTABLE__elementorPackages","editor"] ***!
58
- \\***********************************************************/
79
+ /***/ "@elementor/editor-panels":
80
+ /*!*****************************************************!*\\
81
+ !*** external ["elementorPackages","editorPanels"] ***!
82
+ \\*****************************************************/
59
83
  /***/ ((module) => {
60
84
 
61
- module.exports = window["__UNSTABLE__elementorPackages"]["editor"];
85
+ module.exports = window["elementorPackages"]["editorPanels"];
86
+
87
+ /***/ }),
88
+
89
+ /***/ "@other/package-name":
90
+ /*!*************************************!*\\
91
+ !*** external ["otherPackageName"] ***!
92
+ \\*************************************/
93
+ /***/ ((module) => {
94
+
95
+ module.exports = window["otherPackageName"];
62
96
 
63
97
  /***/ }),
64
98
 
@@ -76,7 +110,7 @@ module.exports = window["wp"]["element"];
76
110
  /******/ __webpack_require__ => { // webpackRuntimeModules
77
111
  /******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
78
112
  /******/ var __webpack_exports__ = (__webpack_exec__("./."));
79
- /******/ (window.testGlobalKey = window.testGlobalKey || {}).app = __webpack_exports__;
113
+ /******/ (window.elementorPackages = window.elementorPackages || {}).myAppTest = __webpack_exports__;
80
114
  /******/ }
81
115
  ]);"
82
116
  `;
@@ -13,17 +13,21 @@ jest.mock( 'fs', () => jest.requireActual( 'memfs' ) );
13
13
  describe( '@elementor/externalize-wordpress-assets-webpack-plugin', () => {
14
14
  beforeEach( () => {
15
15
  const fileContent = `
16
- import elementor from '@elementor/editor';
16
+ import editor from '@elementor/editor';
17
+ import editorPanels from '@elementor/editor-panels';
17
18
  import wp from '@wordpress/element';
18
19
  import React from 'react';
19
20
  import ReactDOM from 'react-dom';
20
21
  import other from '@other/package-name';
21
22
 
22
- elementor();
23
+ editor();
24
+ editorPanels();
23
25
  wp();
24
26
  React();
25
27
  ReactDOM();
26
28
  other();
29
+
30
+ export const test = 'This is test for exporting something';
27
31
  `;
28
32
 
29
33
  fs.writeFileSync( path.resolve( '/app.js' ), fileContent );
@@ -37,25 +41,24 @@ describe( '@elementor/externalize-wordpress-assets-webpack-plugin', () => {
37
41
  // Arrange.
38
42
  const compiler = webpack( {
39
43
  mode: 'development',
40
- entry: {
41
- app: path.resolve( '/app.js' ),
42
- },
44
+ devtool: false,
45
+ entry: { 'my-app-test': path.resolve( '/app.js' ) },
43
46
  context: path.resolve( '/app.js' ),
44
- optimization: {
45
- runtimeChunk: 'single',
46
- },
47
+ optimization: { runtimeChunk: 'single' },
47
48
  output: {
48
49
  filename: '[name].js',
49
50
  path: path.resolve( '/dist' ),
50
51
  },
51
52
  plugins: [
52
53
  new ExternalizeWordPressAssetsWebpackPlugin( {
53
- globalKey: 'testGlobalKey',
54
- externalsMap: {
55
- exact: {
56
- '@other/package-name': 'otherPackageName',
57
- },
58
- },
54
+ global: ( entryName ) => [ 'elementorPackages', entryName ],
55
+ map: [
56
+ { request: 'react', global: 'React' },
57
+ { request: 'react-dom', global: 'ReactDOM' },
58
+ { request: /^@elementor\/(.+)$/, global: [ 'elementorPackages', '$1' ] },
59
+ { request: /^@wordpress\/(.+)$/, global: [ 'wp', '$1' ] },
60
+ { request: '@other/package-name', global: 'otherPackageName' },
61
+ ],
59
62
  } ),
60
63
  ],
61
64
  } );
@@ -70,7 +73,7 @@ describe( '@elementor/externalize-wordpress-assets-webpack-plugin', () => {
70
73
  expect( stats?.hasErrors() ).toBe( false );
71
74
  expect( stats?.hasWarnings() ).toBe( false );
72
75
 
73
- const fileContent = fs.readFileSync( path.resolve( `/dist/app.js` ), { encoding: 'utf8' } );
76
+ const fileContent = fs.readFileSync( path.resolve( `/dist/my-app-test.js` ), { encoding: 'utf8' } );
74
77
 
75
78
  expect( fileContent ).toMatchSnapshot();
76
79
 
package/src/index.ts CHANGED
@@ -1,116 +1 @@
1
- import { ExternalsPlugin, Compiler } from 'webpack';
2
-
3
- type ExternalsMap = {
4
- exact: Record<string, string>;
5
- startsWith: Record<string, string>;
6
- };
7
-
8
- type NormalizedOptions = {
9
- globalKey: string,
10
- externalsMap: ExternalsMap
11
- };
12
-
13
- type Options = {
14
- globalKey: string,
15
- externalsMap?: Partial<ExternalsMap>
16
- };
17
-
18
- const baseExternalsMap: ExternalsMap = {
19
- exact: {
20
- react: 'React',
21
- 'react-dom': 'ReactDOM',
22
- },
23
- startsWith: {
24
- '@elementor/': '__UNSTABLE__elementorPackages',
25
- '@wordpress/': 'wp',
26
- },
27
- };
28
-
29
- export class ExternalizeWordPressAssetsWebpackPlugin {
30
- externalPlugin: ExternalsPlugin;
31
-
32
- options: NormalizedOptions;
33
-
34
- constructor( options: Options ) {
35
- this.options = this.normalizeOptions( options );
36
-
37
- this.externalPlugin = new ExternalsPlugin(
38
- 'window',
39
- ( { request }, callback ) => {
40
- const externalRequest = this.requestToExternal( request );
41
-
42
- if ( externalRequest ) {
43
- return callback( undefined, externalRequest );
44
- }
45
-
46
- return callback();
47
- }
48
- );
49
- }
50
-
51
- apply( compiler: Compiler ) {
52
- this.externalPlugin.apply( compiler );
53
-
54
- compiler.hooks.environment.tap( this.constructor.name, () => {
55
- this.exportAsWindowItem( compiler );
56
- } );
57
- }
58
-
59
- requestToExternal( request?: string ) {
60
- if ( ! request ) {
61
- return;
62
- }
63
-
64
- const { exact, startsWith } = this.options.externalsMap;
65
-
66
- if ( Object.keys( exact ).includes( request ) ) {
67
- return exact[ request ];
68
- }
69
-
70
- for ( const [ prefix, globalKey ] of Object.entries( startsWith ) ) {
71
- if ( request.startsWith( prefix ) ) {
72
- return [ globalKey, this.kebabToCamelCase( request.replace( prefix, '' ) ) ];
73
- }
74
- }
75
- }
76
-
77
- exportAsWindowItem( compiler: Compiler ) {
78
- compiler.options.output.enabledLibraryTypes?.push( 'window' );
79
-
80
- compiler.options.entry = Object.fromEntries(
81
- Object.entries( compiler.options.entry ).map( ( [ name, entry ] ) => [
82
- name,
83
- {
84
- ...entry,
85
- library: {
86
- name: [ this.options.globalKey, this.kebabToCamelCase( name ) ],
87
- type: 'window',
88
- },
89
- },
90
- ] )
91
- );
92
- }
93
-
94
- kebabToCamelCase( kebabCase: string ) {
95
- return kebabCase.replace(
96
- /-(\w)/g,
97
- ( _, w: string ) => w.toUpperCase()
98
- );
99
- }
100
-
101
- normalizeOptions( options: Options ): NormalizedOptions {
102
- return {
103
- ...( options || {} ),
104
- externalsMap: {
105
- exact: {
106
- ...baseExternalsMap.exact,
107
- ...( options?.externalsMap?.exact || {} ),
108
- },
109
- startsWith: {
110
- ...baseExternalsMap.startsWith,
111
- ...( options?.externalsMap?.startsWith || {} ),
112
- },
113
- },
114
- };
115
- }
116
- }
1
+ export { default as ExternalizeWordPressAssetsWebpackPlugin } from './plugin';
package/src/plugin.ts ADDED
@@ -0,0 +1,74 @@
1
+ import { ExternalsPlugin, Compiler } from 'webpack';
2
+ import { kebabToCamelCase, transformRequestToGlobal } from './utils';
3
+ import { RequestToGlobalMap, Global } from './types';
4
+
5
+ type Options = {
6
+ type: string,
7
+ global?: ( entryName: string ) => Global,
8
+ map: RequestToGlobalMap
9
+ };
10
+
11
+ export default class ExternalizeWordPressAssetsWebpackPlugin {
12
+ options: Options;
13
+
14
+ externalPlugin: ExternalsPlugin;
15
+
16
+ constructor( options: Pick<Options, 'map' | 'global'> ) {
17
+ this.options = {
18
+ map: options.map,
19
+ global: options.global,
20
+ type: 'window',
21
+ };
22
+
23
+ this.externalPlugin = new ExternalsPlugin(
24
+ this.options.type,
25
+ ( { request }, callback ) => this.externalsPluginCallback( request, callback )
26
+ );
27
+ }
28
+
29
+ apply( compiler: Compiler ) {
30
+ this.externalPlugin.apply( compiler );
31
+
32
+ compiler.hooks.environment.tap( this.constructor.name, () => {
33
+ this.exposeEntry( compiler );
34
+ } );
35
+ }
36
+
37
+ externalsPluginCallback(
38
+ request: string | undefined,
39
+ callback: ( err?: undefined, result?: Global ) => void
40
+ ) {
41
+ const global = transformRequestToGlobal( request, this.options.map );
42
+
43
+ if ( ! global ) {
44
+ callback();
45
+
46
+ return;
47
+ }
48
+
49
+ callback( undefined, global );
50
+ }
51
+
52
+ exposeEntry( compiler: Compiler ) {
53
+ compiler.options.output.enabledLibraryTypes?.push( this.options.type );
54
+
55
+ const transformEntryNameToGlobal = this.options.global;
56
+ const entry = compiler.options.entry;
57
+
58
+ if ( ! transformEntryNameToGlobal ) {
59
+ return;
60
+ }
61
+
62
+ compiler.options.entry = Object.entries( entry )
63
+ .reduce( ( carry, [ name, entryItem ] ) => ( {
64
+ ...carry,
65
+ [ name ]: {
66
+ ...entryItem,
67
+ library: {
68
+ name: transformEntryNameToGlobal( kebabToCamelCase( name ) ),
69
+ type: this.options.type,
70
+ },
71
+ },
72
+ } ), {} );
73
+ }
74
+ }
package/src/types.ts ADDED
@@ -0,0 +1,6 @@
1
+ export type Global = string | string[];
2
+
3
+ export type RequestToGlobalMap = Array<{
4
+ request: string | RegExp,
5
+ global: Global
6
+ }>
package/src/utils.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { RequestToGlobalMap } from './types';
2
+
3
+ export function transformRequestToGlobal( request: string | undefined, map: RequestToGlobalMap ) {
4
+ if ( ! request ) {
5
+ return null;
6
+ }
7
+
8
+ for ( const item of map ) {
9
+ let { request: requestRegex, global } = item;
10
+
11
+ if ( ! ( requestRegex instanceof RegExp ) ) {
12
+ requestRegex = new RegExp( `^${ requestRegex }$` );
13
+ }
14
+
15
+ const matches = request.match( requestRegex );
16
+
17
+ if ( matches ) {
18
+ return replaceGlobal( global, matches );
19
+ }
20
+ }
21
+
22
+ return null;
23
+ }
24
+
25
+ export function replaceGlobal( global: string | string[], matches: RegExpMatchArray ) {
26
+ let result = typeof global === 'string' ? [ global ] : [ ...global ];
27
+
28
+ matches.forEach( ( value, index ) => {
29
+ // Replace regex backreferences with capture groups.
30
+ // The user can set ['something', '$1', 'a', '$2'] in the global, and the backreferences will
31
+ // be replaced by the matched groups in the regex.
32
+ result = result.map( ( item ) => item.replace( `$${ index }`, kebabToCamelCase( value ) ) );
33
+ } );
34
+
35
+ return result;
36
+ }
37
+
38
+ export function kebabToCamelCase( kebabCase: string ) {
39
+ return kebabCase.replace(
40
+ /-(\w)/g,
41
+ ( _, w: string ) => w.toUpperCase()
42
+ );
43
+ }