@elementor/generate-wordpress-asset-file-webpack-plugin 0.2.1 → 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 CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.3.0](https://github.com/elementor/elementor-packages/compare/@elementor/generate-wordpress-asset-file-webpack-plugin@0.2.1...@elementor/generate-wordpress-asset-file-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
+
6
17
  ## 0.2.1 (2023-07-02)
7
18
 
8
19
  **Note:** Version bump only for package @elementor/generate-wordpress-asset-file-webpack-plugin
package/dist/index.d.mts CHANGED
@@ -1,47 +1,21 @@
1
1
  import { Compiler, Compilation, Chunk } from 'webpack';
2
2
 
3
- type HandlesMap = {
4
- exact: Record<string, string>;
5
- startsWith: Record<string, string>;
6
- };
3
+ type RequestToHandleMap = Array<{
4
+ request: string | RegExp;
5
+ handle: string;
6
+ }>;
7
+
7
8
  type Options = {
8
- handlePrefix: string;
9
- handlesMap?: Partial<HandlesMap>;
10
- apps?: string[];
11
- extensions?: string[];
12
- i18n?: {
13
- domain: string;
14
- replaceRequestedFile?: boolean;
15
- };
16
- };
17
- type NormalizedOptions = {
18
- handlePrefix: string;
19
- handlesMap: HandlesMap;
20
- apps: string[];
21
- extensions: string[];
22
- i18n: {
23
- domain: string | null;
24
- replaceRequestedFile: boolean;
25
- };
9
+ handle: (entryName: string) => string;
10
+ map: RequestToHandleMap;
26
11
  };
27
12
  declare class GenerateWordPressAssetFileWebpackPlugin {
28
- options: NormalizedOptions;
13
+ options: Options;
29
14
  constructor(options: Options);
30
15
  apply(compiler: Compiler): void;
31
- getDepsFromChunk(compilation: Compilation, chunk: Chunk): Set<string>;
32
- createAssetsFileContent({ deps, i18n, entryName, }: {
33
- deps: Set<string>;
34
- i18n: NormalizedOptions['i18n'];
35
- entryName: string;
36
- }): string;
37
- getLoaderFileContent(entriesData: Record<string, string>): string;
38
- getEntryType(entryName: string): "extension" | "app" | "util";
16
+ addAssetFileToEntrypoint(compilation: Compilation, entryName: string, chunk: Chunk): void;
17
+ getDepsHandlesFromChunk(compilation: Compilation, chunk: Chunk): string[];
39
18
  getFileFromChunk(chunk: Chunk): string | undefined;
40
- isExternalDep(request: string): boolean | "";
41
- getHandleFromDep(dep: string): string;
42
- generateHandleName(name: string): string;
43
- generateAssetsFileName(filename: string): string;
44
- normalizeOptions(options: Options): NormalizedOptions;
45
19
  }
46
20
 
47
21
  export { GenerateWordPressAssetFileWebpackPlugin };
package/dist/index.d.ts CHANGED
@@ -1,47 +1,21 @@
1
1
  import { Compiler, Compilation, Chunk } from 'webpack';
2
2
 
3
- type HandlesMap = {
4
- exact: Record<string, string>;
5
- startsWith: Record<string, string>;
6
- };
3
+ type RequestToHandleMap = Array<{
4
+ request: string | RegExp;
5
+ handle: string;
6
+ }>;
7
+
7
8
  type Options = {
8
- handlePrefix: string;
9
- handlesMap?: Partial<HandlesMap>;
10
- apps?: string[];
11
- extensions?: string[];
12
- i18n?: {
13
- domain: string;
14
- replaceRequestedFile?: boolean;
15
- };
16
- };
17
- type NormalizedOptions = {
18
- handlePrefix: string;
19
- handlesMap: HandlesMap;
20
- apps: string[];
21
- extensions: string[];
22
- i18n: {
23
- domain: string | null;
24
- replaceRequestedFile: boolean;
25
- };
9
+ handle: (entryName: string) => string;
10
+ map: RequestToHandleMap;
26
11
  };
27
12
  declare class GenerateWordPressAssetFileWebpackPlugin {
28
- options: NormalizedOptions;
13
+ options: Options;
29
14
  constructor(options: Options);
30
15
  apply(compiler: Compiler): void;
31
- getDepsFromChunk(compilation: Compilation, chunk: Chunk): Set<string>;
32
- createAssetsFileContent({ deps, i18n, entryName, }: {
33
- deps: Set<string>;
34
- i18n: NormalizedOptions['i18n'];
35
- entryName: string;
36
- }): string;
37
- getLoaderFileContent(entriesData: Record<string, string>): string;
38
- getEntryType(entryName: string): "extension" | "app" | "util";
16
+ addAssetFileToEntrypoint(compilation: Compilation, entryName: string, chunk: Chunk): void;
17
+ getDepsHandlesFromChunk(compilation: Compilation, chunk: Chunk): string[];
39
18
  getFileFromChunk(chunk: Chunk): string | undefined;
40
- isExternalDep(request: string): boolean | "";
41
- getHandleFromDep(dep: string): string;
42
- generateHandleName(name: string): string;
43
- generateAssetsFileName(filename: string): string;
44
- normalizeOptions(options: Options): NormalizedOptions;
45
19
  }
46
20
 
47
21
  export { GenerateWordPressAssetFileWebpackPlugin };
package/dist/index.js CHANGED
@@ -23,176 +23,98 @@ __export(src_exports, {
23
23
  GenerateWordPressAssetFileWebpackPlugin: () => GenerateWordPressAssetFileWebpackPlugin
24
24
  });
25
25
  module.exports = __toCommonJS(src_exports);
26
+
27
+ // src/plugin.ts
26
28
  var import_webpack = require("webpack");
27
- var baseHandlesMap = {
28
- exact: {
29
- react: "react",
30
- "react-dom": "react-dom"
31
- },
32
- startsWith: {
33
- "@elementor/": "elementor-packages-",
34
- "@wordpress/": "wp-"
29
+
30
+ // src/utils.ts
31
+ function getAssetFileContent(entryHandle, depsHandles) {
32
+ const depsAsString = depsHandles.filter((dep) => dep !== entryHandle).sort().map((dep) => `'${dep}',`).join("\n ");
33
+ return `<?php
34
+ if ( ! defined( 'ABSPATH' ) ) {
35
+ exit;
36
+ }
37
+ /**
38
+ * This file is generated by Webpack, do not edit it directly.
39
+ */
40
+ return [
41
+ 'handle' => '${entryHandle}',
42
+ 'deps' => [
43
+ ${depsAsString}
44
+ ],
45
+ ];
46
+ `;
47
+ }
48
+ function transformRequestToHandle(request, map) {
49
+ if (!request) {
50
+ return request;
35
51
  }
36
- };
52
+ for (const item of map) {
53
+ let { request: requestRegex, handle } = item;
54
+ if (!(requestRegex instanceof RegExp)) {
55
+ requestRegex = new RegExp(`^${requestRegex}$`);
56
+ }
57
+ const matches = request.match(requestRegex);
58
+ if (matches) {
59
+ return request.replace(requestRegex, handle);
60
+ }
61
+ }
62
+ }
63
+ function createAssetFilePath(path, suffix = ".asset.php") {
64
+ return path.replace(/(\.min)?\.js$/i, suffix);
65
+ }
66
+
67
+ // src/plugin.ts
37
68
  var GenerateWordPressAssetFileWebpackPlugin = class {
38
69
  options;
39
70
  constructor(options) {
40
- this.options = this.normalizeOptions(options);
71
+ this.options = options;
41
72
  }
42
73
  apply(compiler) {
43
74
  compiler.hooks.thisCompilation.tap(this.constructor.name, (compilation) => {
44
- let handlesAssetsMap;
45
75
  compilation.hooks.processAssets.tap({ name: this.constructor.name }, () => {
46
- handlesAssetsMap = [...compilation.entrypoints].reduce((map, [entryName, entrypoint]) => {
76
+ [...compilation.entrypoints].forEach(([entryName, entrypoint]) => {
47
77
  const chunk = entrypoint.chunks.find(({ name }) => name === entryName);
48
78
  if (!chunk) {
49
- return map;
50
- }
51
- const chunkJSFile = this.getFileFromChunk(chunk);
52
- if (!chunkJSFile) {
53
- return map;
79
+ return;
54
80
  }
55
- const deps = this.getDepsFromChunk(compilation, chunk);
56
- const assetFilename = this.generateAssetsFileName(
57
- compilation.getPath("[file]", { filename: chunkJSFile })
58
- );
59
- const handle = this.generateHandleName(entryName);
60
- const content = this.createAssetsFileContent({
61
- deps,
62
- entryName,
63
- i18n: this.options.i18n
64
- });
65
- compilation.assets[assetFilename] = new import_webpack.sources.RawSource(content);
66
- chunk.files.add(assetFilename);
67
- map[handle] = assetFilename;
68
- return map;
69
- }, {});
70
- });
71
- compilation.hooks.afterProcessAssets.tap({ name: this.constructor.name }, () => {
72
- const loaderFileContent = this.getLoaderFileContent(handlesAssetsMap);
73
- compilation.assets["loader.php"] = new import_webpack.sources.RawSource(loaderFileContent);
81
+ this.addAssetFileToEntrypoint(compilation, entryName, chunk);
82
+ });
74
83
  });
75
84
  });
76
85
  }
77
- getDepsFromChunk(compilation, chunk) {
86
+ addAssetFileToEntrypoint(compilation, entryName, chunk) {
87
+ const chunkJSFile = this.getFileFromChunk(chunk);
88
+ if (!chunkJSFile) {
89
+ return;
90
+ }
91
+ const transformEntryNameToHandle = this.options.handle;
92
+ const entryHandle = transformEntryNameToHandle(entryName);
93
+ const depsHandles = this.getDepsHandlesFromChunk(compilation, chunk);
94
+ const assetFilePath = createAssetFilePath(
95
+ compilation.getPath("[file]", { filename: chunkJSFile })
96
+ );
97
+ compilation.assets[assetFilePath] = new import_webpack.sources.RawSource(
98
+ getAssetFileContent(entryHandle, depsHandles)
99
+ );
100
+ chunk.files.add(assetFilePath);
101
+ }
102
+ getDepsHandlesFromChunk(compilation, chunk) {
78
103
  const depsSet = /* @__PURE__ */ new Set();
79
104
  compilation.chunkGraph.getChunkModules(chunk).forEach((module2) => {
80
105
  const theModule = module2;
81
106
  [...theModule.modules || [], theModule].forEach((subModule) => {
82
- if (subModule.userRequest && this.isExternalDep(subModule.userRequest)) {
83
- depsSet.add(subModule.userRequest);
107
+ const depHandle = transformRequestToHandle(subModule.userRequest, this.options.map);
108
+ if (depHandle) {
109
+ depsSet.add(depHandle);
84
110
  }
85
111
  });
86
112
  });
87
- return depsSet;
88
- }
89
- createAssetsFileContent({
90
- deps,
91
- i18n,
92
- entryName
93
- }) {
94
- const handleName = this.generateHandleName(entryName);
95
- const type = this.getEntryType(entryName);
96
- const depsAsString = [...deps].map((dep) => this.getHandleFromDep(dep)).filter((dep) => dep !== handleName).sort().map((dep) => `'${dep}',`).join("\n ");
97
- const i18nContent = i18n.domain ? `[
98
- 'domain' => '${i18n.domain}',
99
- 'replace_requested_file' => ${(i18n.replaceRequestedFile ?? false).toString()},
100
- ]` : "[]";
101
- const content = `<?php
102
- if ( ! defined( 'ABSPATH' ) ) {
103
- exit;
104
- }
105
- /**
106
- * This file is generated by Webpack, do not edit it directly.
107
- */
108
- return [
109
- 'handle' => '${handleName}',
110
- 'src' => plugins_url( '/', __FILE__ ) . '${entryName}{{MIN_SUFFIX}}.js',
111
- 'i18n' => ${i18nContent},
112
- 'type' => '${type}',
113
- 'deps' => [
114
- ${depsAsString}
115
- ],
116
- ];
117
- `;
118
- return content;
119
- }
120
- getLoaderFileContent(entriesData) {
121
- const entriesContent = Object.entries(entriesData).map(([handle, assetFileName]) => {
122
- return `
123
- $data['${handle}'] = require __DIR__ . '/${assetFileName}';`;
124
- });
125
- return `<?php
126
- if ( ! defined( 'ABSPATH' ) ) {
127
- exit;
128
- }
129
- /**
130
- * This file is generated by Webpack, do not edit it directly.
131
- */
132
- add_filter( 'elementor/editor-v2/packages/config', function( $data ) {
133
- ${entriesContent.join("\n")}
134
- return $data;
135
- } );
136
- `;
137
- }
138
- getEntryType(entryName) {
139
- if (this.options.extensions.includes(entryName)) {
140
- return "extension";
141
- }
142
- if (this.options.apps.includes(entryName)) {
143
- return "app";
144
- }
145
- return "util";
113
+ return [...depsSet];
146
114
  }
147
115
  getFileFromChunk(chunk) {
148
116
  return [...chunk.files].find((f) => /\.js$/i.test(f));
149
117
  }
150
- isExternalDep(request) {
151
- const { startsWith, exact } = this.options.handlesMap;
152
- return request && (Object.keys(exact).includes(request) || Object.keys(startsWith).some((dep) => request.startsWith(dep)));
153
- }
154
- getHandleFromDep(dep) {
155
- const { startsWith, exact } = this.options.handlesMap;
156
- if (Object.keys(exact).includes(dep)) {
157
- return exact[dep];
158
- }
159
- for (const [key, value] of Object.entries(startsWith)) {
160
- if (dep.startsWith(key)) {
161
- return dep.replace(key, value);
162
- }
163
- }
164
- return dep;
165
- }
166
- generateHandleName(name) {
167
- if (this.options.handlePrefix) {
168
- return `${this.options.handlePrefix}${name}`;
169
- }
170
- return name;
171
- }
172
- generateAssetsFileName(filename) {
173
- return filename.replace(/(\.min)?\.js$/i, ".asset.php");
174
- }
175
- normalizeOptions(options) {
176
- return {
177
- ...options,
178
- handlesMap: {
179
- exact: {
180
- ...baseHandlesMap.exact,
181
- ...options?.handlesMap?.exact || {}
182
- },
183
- startsWith: {
184
- ...baseHandlesMap.startsWith,
185
- ...options?.handlesMap?.startsWith || {}
186
- }
187
- },
188
- apps: options?.apps || [],
189
- extensions: options?.extensions || [],
190
- i18n: {
191
- domain: options?.i18n?.domain || null,
192
- replaceRequestedFile: options?.i18n?.replaceRequestedFile ?? false
193
- }
194
- };
195
- }
196
118
  };
197
119
  // Annotate the CommonJS export names for ESM import in node:
198
120
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Inspired by \"Dependency Extraction Webpack Plugin\" by @wordpress team.\n// Link: https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin\nimport { sources, Compilation, Compiler, Chunk } from 'webpack';\n\ntype HandlesMap = {\n\texact: Record<string, string>;\n\tstartsWith: Record<string, string>;\n}\n\ntype Options = {\n\thandlePrefix: string;\n\thandlesMap?: Partial<HandlesMap>\n\tapps?: string[];\n\textensions?: string[];\n\ti18n?: {\n\t\tdomain: string;\n\t\treplaceRequestedFile?: boolean;\n\t}\n}\n\ntype NormalizedOptions = {\n\thandlePrefix: string;\n\thandlesMap: HandlesMap;\n\tapps: string[];\n\textensions: string[];\n\ti18n: {\n\t\tdomain: string | null;\n\t\treplaceRequestedFile: boolean;\n\t}\n}\n\ntype Module = {\n\tuserRequest?: string;\n\tmodules?: Module[];\n}\n\nconst baseHandlesMap: HandlesMap = {\n\texact: {\n\t\treact: 'react',\n\t\t'react-dom': 'react-dom',\n\t},\n\tstartsWith: {\n\t\t'@elementor/': 'elementor-packages-',\n\t\t'@wordpress/': 'wp-',\n\t},\n};\n\nexport class GenerateWordPressAssetFileWebpackPlugin {\n\toptions: NormalizedOptions;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = this.normalizeOptions( options );\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.thisCompilation.tap( this.constructor.name, ( compilation ) => {\n\t\t\tlet handlesAssetsMap: Record<string, string>;\n\n\t\t\tcompilation.hooks.processAssets.tap( { name: this.constructor.name }, () => {\n\t\t\t\thandlesAssetsMap = [ ...compilation.entrypoints ].reduce<Record<string, string>>( ( map, [ entryName, entrypoint ] ) => {\n\t\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === entryName );\n\n\t\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\t\treturn map;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst chunkJSFile = this.getFileFromChunk( chunk );\n\n\t\t\t\t\tif ( ! chunkJSFile ) {\n\t\t\t\t\t\treturn map;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst deps = this.getDepsFromChunk( compilation, chunk );\n\n\t\t\t\t\tconst assetFilename = this.generateAssetsFileName(\n\t\t\t\t\t\tcompilation.getPath( '[file]', { filename: chunkJSFile } )\n\t\t\t\t\t);\n\n\t\t\t\t\tconst handle = this.generateHandleName( entryName );\n\n\t\t\t\t\tconst content = this.createAssetsFileContent( {\n\t\t\t\t\t\tdeps,\n\t\t\t\t\t\tentryName,\n\t\t\t\t\t\ti18n: this.options.i18n,\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Add source and file into compilation for webpack to output.\n\t\t\t\t\tcompilation.assets[ assetFilename ] = new sources.RawSource( content );\n\n\t\t\t\t\tchunk.files.add( assetFilename );\n\n\t\t\t\t\tmap[ handle ] = assetFilename;\n\n\t\t\t\t\treturn map;\n\t\t\t\t}, {} );\n\t\t\t} );\n\n\t\t\tcompilation.hooks.afterProcessAssets.tap( { name: this.constructor.name }, () => {\n\t\t\t\tconst loaderFileContent = this.getLoaderFileContent( handlesAssetsMap );\n\n\t\t\t\tcompilation.assets[ 'loader.php' ] = new sources.RawSource( loaderFileContent );\n\t\t\t} );\n\t\t} );\n\t}\n\n\tgetDepsFromChunk( compilation: Compilation, chunk: Chunk ) {\n\t\tconst depsSet = new Set<string>();\n\n\t\tcompilation.chunkGraph.getChunkModules( chunk ).forEach( ( module ) => {\n\t\t\t// There are some issues with types in webpack, so we need to cast it.\n\t\t\tconst theModule = module as Module;\n\n\t\t\t[ ...( theModule.modules || [] ), theModule ].forEach( ( subModule ) => {\n\t\t\t\tif ( subModule.userRequest && this.isExternalDep( subModule.userRequest ) ) {\n\t\t\t\t\tdepsSet.add( subModule.userRequest );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\treturn depsSet;\n\t}\n\n\tcreateAssetsFileContent( {\n\t\tdeps,\n\t\ti18n,\n\t\tentryName,\n\t}: {\n\t\tdeps: Set<string>;\n\t\ti18n: NormalizedOptions[ 'i18n' ];\n\t\tentryName: string;\n\t} ) {\n\t\tconst handleName = this.generateHandleName( entryName );\n\t\tconst type = this.getEntryType( entryName );\n\n\t\tconst depsAsString = [ ...deps ]\n\t\t\t.map( ( dep ) => this.getHandleFromDep( dep ) )\n\t\t\t.filter( ( dep ) => dep !== handleName )\n\t\t\t.sort()\n\t\t\t.map( ( dep ) => `'${ dep }',` )\n\t\t\t.join( '\\n\\t\\t' );\n\n\t\tconst i18nContent = i18n.domain ? `[\n\t\t'domain' => '${ i18n.domain }',\n\t\t'replace_requested_file' => ${ ( i18n.replaceRequestedFile ?? false ).toString() },\n\t]` : '[]';\n\n\t\tconst content =\n\t\t\t`<?php\nif ( ! defined( 'ABSPATH' ) ) {\n\texit;\n}\n/**\n * This file is generated by Webpack, do not edit it directly.\n */\nreturn [\n\t'handle' => '${ handleName }',\n\t'src' => plugins_url( '/', __FILE__ ) . '${ entryName }{{MIN_SUFFIX}}.js',\n\t'i18n' => ${ i18nContent },\n\t'type' => '${ type }',\n\t'deps' => [\n\t\t${ depsAsString }\n\t],\n];\n`;\n\n\t\treturn content;\n\t}\n\n\tgetLoaderFileContent( entriesData: Record<string, string> ) {\n\t\tconst entriesContent = Object.entries( entriesData ).map( ( [ handle, assetFileName ] ) => {\n\t\t\treturn `\n\t$data['${ handle }'] = require __DIR__ . '/${ assetFileName }';`;\n\t\t} );\n\n\t\treturn `<?php\nif ( ! defined( 'ABSPATH' ) ) {\n\texit;\n}\n/**\n * This file is generated by Webpack, do not edit it directly.\n */\nadd_filter( 'elementor/editor-v2/packages/config', function( $data ) {\n${ entriesContent.join( '\\n' ) }\n\treturn $data;\n} );\n`;\n\t}\n\n\tgetEntryType( entryName: string ) {\n\t\tif ( this.options.extensions.includes( entryName ) ) {\n\t\t\treturn 'extension';\n\t\t}\n\n\t\tif ( this.options.apps.includes( entryName ) ) {\n\t\t\treturn 'app';\n\t\t}\n\n\t\treturn 'util';\n\t}\n\n\tgetFileFromChunk( chunk: Chunk ) {\n\t\treturn [ ...chunk.files ].find( ( f ) => /\\.js$/i.test( f ) );\n\t}\n\n\tisExternalDep( request: string ) {\n\t\tconst { startsWith, exact } = this.options.handlesMap;\n\n\t\treturn request && (\n\t\t\tObject.keys( exact ).includes( request ) ||\n\t\t\tObject.keys( startsWith ).some( ( dep ) => request.startsWith( dep ) )\n\t\t);\n\t}\n\n\tgetHandleFromDep( dep: string ) {\n\t\tconst { startsWith, exact } = this.options.handlesMap;\n\n\t\tif ( Object.keys( exact ).includes( dep ) ) {\n\t\t\treturn exact[ dep ];\n\t\t}\n\n\t\tfor ( const [ key, value ] of Object.entries( startsWith ) ) {\n\t\t\tif ( dep.startsWith( key ) ) {\n\t\t\t\treturn dep.replace( key, value );\n\t\t\t}\n\t\t}\n\n\t\treturn dep;\n\t}\n\n\tgenerateHandleName( name: string ) {\n\t\tif ( this.options.handlePrefix ) {\n\t\t\treturn `${ this.options.handlePrefix }${ name }`;\n\t\t}\n\n\t\treturn name;\n\t}\n\n\tgenerateAssetsFileName( filename: string ) {\n\t\treturn filename.replace( /(\\.min)?\\.js$/i, '.asset.php' );\n\t}\n\n\tnormalizeOptions( options: Options ): NormalizedOptions {\n\t\treturn {\n\t\t\t...options,\n\t\t\thandlesMap: {\n\t\t\t\texact: {\n\t\t\t\t\t...baseHandlesMap.exact,\n\t\t\t\t\t...( options?.handlesMap?.exact || {} ),\n\t\t\t\t},\n\t\t\t\tstartsWith: {\n\t\t\t\t\t...baseHandlesMap.startsWith,\n\t\t\t\t\t...( options?.handlesMap?.startsWith || {} ),\n\t\t\t\t},\n\t\t\t},\n\t\t\tapps: options?.apps || [],\n\t\t\textensions: options?.extensions || [],\n\t\t\ti18n: {\n\t\t\t\tdomain: options?.i18n?.domain || null,\n\t\t\t\treplaceRequestedFile: options?.i18n?.replaceRequestedFile ?? false,\n\t\t\t},\n\t\t};\n\t}\n}\n"],"mappings":"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","names":["module"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/utils.ts"],"sourcesContent":["export { default as GenerateWordPressAssetFileWebpackPlugin } from './plugin';\n","// Inspired by \"Dependency Extraction Webpack Plugin\" by @wordpress team.\n// Link: https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin\nimport { sources, Compilation, Compiler, Chunk } from 'webpack';\nimport { createAssetFilePath, getAssetFileContent, transformRequestToHandle } from './utils';\nimport { RequestToHandleMap } from './types';\n\ntype Options = {\n\thandle: ( entryName: string ) => string;\n\tmap: RequestToHandleMap\n}\n\ntype Module = {\n\tuserRequest?: string;\n\tmodules?: Module[];\n}\n\nexport default class GenerateWordPressAssetFileWebpackPlugin {\n\toptions: Options;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = options;\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.thisCompilation.tap( this.constructor.name, ( compilation ) => {\n\t\t\tcompilation.hooks.processAssets.tap( { name: this.constructor.name }, () => {\n\t\t\t\t[ ...compilation.entrypoints ].forEach( ( [ entryName, entrypoint ] ) => {\n\t\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === entryName );\n\n\t\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addAssetFileToEntrypoint( compilation, entryName, chunk );\n\t\t\t\t} );\n\t\t\t} );\n\t\t} );\n\t}\n\n\taddAssetFileToEntrypoint( compilation: Compilation, entryName: string, chunk: Chunk ) {\n\t\tconst chunkJSFile = this.getFileFromChunk( chunk );\n\n\t\tif ( ! chunkJSFile ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst transformEntryNameToHandle = this.options.handle;\n\n\t\tconst entryHandle = transformEntryNameToHandle( entryName );\n\t\tconst depsHandles = this.getDepsHandlesFromChunk( compilation, chunk );\n\n\t\tconst assetFilePath = createAssetFilePath(\n\t\t\tcompilation.getPath( '[file]', { filename: chunkJSFile } )\n\t\t);\n\n\t\t// Add source and file into compilation for webpack to output.\n\t\tcompilation.assets[ assetFilePath ] = new sources.RawSource(\n\t\t\tgetAssetFileContent( entryHandle, depsHandles )\n\t\t);\n\n\t\tchunk.files.add( assetFilePath );\n\t}\n\n\tgetDepsHandlesFromChunk( compilation: Compilation, chunk: Chunk ) {\n\t\tconst depsSet = new Set<string>();\n\n\t\tcompilation.chunkGraph.getChunkModules( chunk ).forEach( ( module ) => {\n\t\t\t// There are some issues with types in webpack, so we need to cast it.\n\t\t\tconst theModule = module as Module;\n\n\t\t\t[ ...( theModule.modules || [] ), theModule ].forEach( ( subModule ) => {\n\t\t\t\tconst depHandle = transformRequestToHandle( subModule.userRequest, this.options.map );\n\n\t\t\t\tif ( depHandle ) {\n\t\t\t\t\tdepsSet.add( depHandle );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\treturn [ ...depsSet ];\n\t}\n\n\tgetFileFromChunk( chunk: Chunk ) {\n\t\treturn [ ...chunk.files ].find( ( f ) => /\\.js$/i.test( f ) );\n\t}\n}\n","import { RequestToHandleMap } from './types';\n\nexport function getAssetFileContent( entryHandle: string, depsHandles: string[] ) {\n\tconst depsAsString = depsHandles\n\t\t.filter( ( dep ) => dep !== entryHandle )\n\t\t.sort()\n\t\t.map( ( dep ) => `'${ dep }',` )\n\t\t.join( '\\n\\t\\t' );\n\n\treturn `<?php\nif ( ! defined( 'ABSPATH' ) ) {\n\texit;\n}\n/**\n * This file is generated by Webpack, do not edit it directly.\n */\nreturn [\n\t'handle' => '${ entryHandle }',\n\t'deps' => [\n\t\t${ depsAsString }\n\t],\n];\n`;\n}\n\nexport function transformRequestToHandle( request: string | undefined, map: RequestToHandleMap ) {\n\tif ( ! request ) {\n\t\treturn request;\n\t}\n\n\tfor ( const item of map ) {\n\t\tlet { request: requestRegex, handle } = 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 request.replace( requestRegex, handle );\n\t\t}\n\t}\n}\n\nexport function createAssetFilePath( path: string, suffix = '.asset.php' ) {\n\treturn path.replace( /(\\.min)?\\.js$/i, suffix );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,qBAAsD;;;ACA/C,SAAS,oBAAqB,aAAqB,aAAwB;AACjF,QAAM,eAAe,YACnB,OAAQ,CAAE,QAAS,QAAQ,WAAY,EACvC,KAAK,EACL,IAAK,CAAE,QAAS,IAAK,GAAI,IAAK,EAC9B,KAAM,MAAS;AAEjB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAQS,WAAY;AAAA;AAAA,IAExB,YAAa;AAAA;AAAA;AAAA;AAIlB;AAEO,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,QAAQ,QAAS,cAAc,MAAO;AAAA,IAC9C;AAAA,EACD;AACD;AAEO,SAAS,oBAAqB,MAAc,SAAS,cAAe;AAC1E,SAAO,KAAK,QAAS,kBAAkB,MAAO;AAC/C;;;AD/BA,IAAqB,0CAArB,MAA6D;AAAA,EAC5D;AAAA,EAEA,YAAa,SAAmB;AAC/B,SAAK,UAAU;AAAA,EAChB;AAAA,EAEA,MAAO,UAAqB;AAC3B,aAAS,MAAM,gBAAgB,IAAK,KAAK,YAAY,MAAM,CAAE,gBAAiB;AAC7E,kBAAY,MAAM,cAAc,IAAK,EAAE,MAAM,KAAK,YAAY,KAAK,GAAG,MAAM;AAC3E,SAAE,GAAG,YAAY,WAAY,EAAE,QAAS,CAAE,CAAE,WAAW,UAAW,MAAO;AACxE,gBAAM,QAAQ,WAAW,OAAO,KAAM,CAAE,EAAE,KAAK,MAAO,SAAS,SAAU;AAEzE,cAAK,CAAE,OAAQ;AACd;AAAA,UACD;AAEA,eAAK,yBAA0B,aAAa,WAAW,KAAM;AAAA,QAC9D,CAAE;AAAA,MACH,CAAE;AAAA,IACH,CAAE;AAAA,EACH;AAAA,EAEA,yBAA0B,aAA0B,WAAmB,OAAe;AACrF,UAAM,cAAc,KAAK,iBAAkB,KAAM;AAEjD,QAAK,CAAE,aAAc;AACpB;AAAA,IACD;AAEA,UAAM,6BAA6B,KAAK,QAAQ;AAEhD,UAAM,cAAc,2BAA4B,SAAU;AAC1D,UAAM,cAAc,KAAK,wBAAyB,aAAa,KAAM;AAErE,UAAM,gBAAgB;AAAA,MACrB,YAAY,QAAS,UAAU,EAAE,UAAU,YAAY,CAAE;AAAA,IAC1D;AAGA,gBAAY,OAAQ,aAAc,IAAI,IAAI,uBAAQ;AAAA,MACjD,oBAAqB,aAAa,WAAY;AAAA,IAC/C;AAEA,UAAM,MAAM,IAAK,aAAc;AAAA,EAChC;AAAA,EAEA,wBAAyB,aAA0B,OAAe;AACjE,UAAM,UAAU,oBAAI,IAAY;AAEhC,gBAAY,WAAW,gBAAiB,KAAM,EAAE,QAAS,CAAEA,YAAY;AAEtE,YAAM,YAAYA;AAElB,OAAE,GAAK,UAAU,WAAW,CAAC,GAAK,SAAU,EAAE,QAAS,CAAE,cAAe;AACvE,cAAM,YAAY,yBAA0B,UAAU,aAAa,KAAK,QAAQ,GAAI;AAEpF,YAAK,WAAY;AAChB,kBAAQ,IAAK,SAAU;AAAA,QACxB;AAAA,MACD,CAAE;AAAA,IACH,CAAE;AAEF,WAAO,CAAE,GAAG,OAAQ;AAAA,EACrB;AAAA,EAEA,iBAAkB,OAAe;AAChC,WAAO,CAAE,GAAG,MAAM,KAAM,EAAE,KAAM,CAAE,MAAO,SAAS,KAAM,CAAE,CAAE;AAAA,EAC7D;AACD;","names":["module"]}
package/dist/index.mjs CHANGED
@@ -1,174 +1,94 @@
1
- // src/index.ts
1
+ // src/plugin.ts
2
2
  import { sources } from "webpack";
3
- var baseHandlesMap = {
4
- exact: {
5
- react: "react",
6
- "react-dom": "react-dom"
7
- },
8
- startsWith: {
9
- "@elementor/": "elementor-packages-",
10
- "@wordpress/": "wp-"
3
+
4
+ // src/utils.ts
5
+ function getAssetFileContent(entryHandle, depsHandles) {
6
+ const depsAsString = depsHandles.filter((dep) => dep !== entryHandle).sort().map((dep) => `'${dep}',`).join("\n ");
7
+ return `<?php
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit;
10
+ }
11
+ /**
12
+ * This file is generated by Webpack, do not edit it directly.
13
+ */
14
+ return [
15
+ 'handle' => '${entryHandle}',
16
+ 'deps' => [
17
+ ${depsAsString}
18
+ ],
19
+ ];
20
+ `;
21
+ }
22
+ function transformRequestToHandle(request, map) {
23
+ if (!request) {
24
+ return request;
11
25
  }
12
- };
26
+ for (const item of map) {
27
+ let { request: requestRegex, handle } = item;
28
+ if (!(requestRegex instanceof RegExp)) {
29
+ requestRegex = new RegExp(`^${requestRegex}$`);
30
+ }
31
+ const matches = request.match(requestRegex);
32
+ if (matches) {
33
+ return request.replace(requestRegex, handle);
34
+ }
35
+ }
36
+ }
37
+ function createAssetFilePath(path, suffix = ".asset.php") {
38
+ return path.replace(/(\.min)?\.js$/i, suffix);
39
+ }
40
+
41
+ // src/plugin.ts
13
42
  var GenerateWordPressAssetFileWebpackPlugin = class {
14
43
  options;
15
44
  constructor(options) {
16
- this.options = this.normalizeOptions(options);
45
+ this.options = options;
17
46
  }
18
47
  apply(compiler) {
19
48
  compiler.hooks.thisCompilation.tap(this.constructor.name, (compilation) => {
20
- let handlesAssetsMap;
21
49
  compilation.hooks.processAssets.tap({ name: this.constructor.name }, () => {
22
- handlesAssetsMap = [...compilation.entrypoints].reduce((map, [entryName, entrypoint]) => {
50
+ [...compilation.entrypoints].forEach(([entryName, entrypoint]) => {
23
51
  const chunk = entrypoint.chunks.find(({ name }) => name === entryName);
24
52
  if (!chunk) {
25
- return map;
53
+ return;
26
54
  }
27
- const chunkJSFile = this.getFileFromChunk(chunk);
28
- if (!chunkJSFile) {
29
- return map;
30
- }
31
- const deps = this.getDepsFromChunk(compilation, chunk);
32
- const assetFilename = this.generateAssetsFileName(
33
- compilation.getPath("[file]", { filename: chunkJSFile })
34
- );
35
- const handle = this.generateHandleName(entryName);
36
- const content = this.createAssetsFileContent({
37
- deps,
38
- entryName,
39
- i18n: this.options.i18n
40
- });
41
- compilation.assets[assetFilename] = new sources.RawSource(content);
42
- chunk.files.add(assetFilename);
43
- map[handle] = assetFilename;
44
- return map;
45
- }, {});
46
- });
47
- compilation.hooks.afterProcessAssets.tap({ name: this.constructor.name }, () => {
48
- const loaderFileContent = this.getLoaderFileContent(handlesAssetsMap);
49
- compilation.assets["loader.php"] = new sources.RawSource(loaderFileContent);
55
+ this.addAssetFileToEntrypoint(compilation, entryName, chunk);
56
+ });
50
57
  });
51
58
  });
52
59
  }
53
- getDepsFromChunk(compilation, chunk) {
60
+ addAssetFileToEntrypoint(compilation, entryName, chunk) {
61
+ const chunkJSFile = this.getFileFromChunk(chunk);
62
+ if (!chunkJSFile) {
63
+ return;
64
+ }
65
+ const transformEntryNameToHandle = this.options.handle;
66
+ const entryHandle = transformEntryNameToHandle(entryName);
67
+ const depsHandles = this.getDepsHandlesFromChunk(compilation, chunk);
68
+ const assetFilePath = createAssetFilePath(
69
+ compilation.getPath("[file]", { filename: chunkJSFile })
70
+ );
71
+ compilation.assets[assetFilePath] = new sources.RawSource(
72
+ getAssetFileContent(entryHandle, depsHandles)
73
+ );
74
+ chunk.files.add(assetFilePath);
75
+ }
76
+ getDepsHandlesFromChunk(compilation, chunk) {
54
77
  const depsSet = /* @__PURE__ */ new Set();
55
78
  compilation.chunkGraph.getChunkModules(chunk).forEach((module) => {
56
79
  const theModule = module;
57
80
  [...theModule.modules || [], theModule].forEach((subModule) => {
58
- if (subModule.userRequest && this.isExternalDep(subModule.userRequest)) {
59
- depsSet.add(subModule.userRequest);
81
+ const depHandle = transformRequestToHandle(subModule.userRequest, this.options.map);
82
+ if (depHandle) {
83
+ depsSet.add(depHandle);
60
84
  }
61
85
  });
62
86
  });
63
- return depsSet;
64
- }
65
- createAssetsFileContent({
66
- deps,
67
- i18n,
68
- entryName
69
- }) {
70
- const handleName = this.generateHandleName(entryName);
71
- const type = this.getEntryType(entryName);
72
- const depsAsString = [...deps].map((dep) => this.getHandleFromDep(dep)).filter((dep) => dep !== handleName).sort().map((dep) => `'${dep}',`).join("\n ");
73
- const i18nContent = i18n.domain ? `[
74
- 'domain' => '${i18n.domain}',
75
- 'replace_requested_file' => ${(i18n.replaceRequestedFile ?? false).toString()},
76
- ]` : "[]";
77
- const content = `<?php
78
- if ( ! defined( 'ABSPATH' ) ) {
79
- exit;
80
- }
81
- /**
82
- * This file is generated by Webpack, do not edit it directly.
83
- */
84
- return [
85
- 'handle' => '${handleName}',
86
- 'src' => plugins_url( '/', __FILE__ ) . '${entryName}{{MIN_SUFFIX}}.js',
87
- 'i18n' => ${i18nContent},
88
- 'type' => '${type}',
89
- 'deps' => [
90
- ${depsAsString}
91
- ],
92
- ];
93
- `;
94
- return content;
95
- }
96
- getLoaderFileContent(entriesData) {
97
- const entriesContent = Object.entries(entriesData).map(([handle, assetFileName]) => {
98
- return `
99
- $data['${handle}'] = require __DIR__ . '/${assetFileName}';`;
100
- });
101
- return `<?php
102
- if ( ! defined( 'ABSPATH' ) ) {
103
- exit;
104
- }
105
- /**
106
- * This file is generated by Webpack, do not edit it directly.
107
- */
108
- add_filter( 'elementor/editor-v2/packages/config', function( $data ) {
109
- ${entriesContent.join("\n")}
110
- return $data;
111
- } );
112
- `;
113
- }
114
- getEntryType(entryName) {
115
- if (this.options.extensions.includes(entryName)) {
116
- return "extension";
117
- }
118
- if (this.options.apps.includes(entryName)) {
119
- return "app";
120
- }
121
- return "util";
87
+ return [...depsSet];
122
88
  }
123
89
  getFileFromChunk(chunk) {
124
90
  return [...chunk.files].find((f) => /\.js$/i.test(f));
125
91
  }
126
- isExternalDep(request) {
127
- const { startsWith, exact } = this.options.handlesMap;
128
- return request && (Object.keys(exact).includes(request) || Object.keys(startsWith).some((dep) => request.startsWith(dep)));
129
- }
130
- getHandleFromDep(dep) {
131
- const { startsWith, exact } = this.options.handlesMap;
132
- if (Object.keys(exact).includes(dep)) {
133
- return exact[dep];
134
- }
135
- for (const [key, value] of Object.entries(startsWith)) {
136
- if (dep.startsWith(key)) {
137
- return dep.replace(key, value);
138
- }
139
- }
140
- return dep;
141
- }
142
- generateHandleName(name) {
143
- if (this.options.handlePrefix) {
144
- return `${this.options.handlePrefix}${name}`;
145
- }
146
- return name;
147
- }
148
- generateAssetsFileName(filename) {
149
- return filename.replace(/(\.min)?\.js$/i, ".asset.php");
150
- }
151
- normalizeOptions(options) {
152
- return {
153
- ...options,
154
- handlesMap: {
155
- exact: {
156
- ...baseHandlesMap.exact,
157
- ...options?.handlesMap?.exact || {}
158
- },
159
- startsWith: {
160
- ...baseHandlesMap.startsWith,
161
- ...options?.handlesMap?.startsWith || {}
162
- }
163
- },
164
- apps: options?.apps || [],
165
- extensions: options?.extensions || [],
166
- i18n: {
167
- domain: options?.i18n?.domain || null,
168
- replaceRequestedFile: options?.i18n?.replaceRequestedFile ?? false
169
- }
170
- };
171
- }
172
92
  };
173
93
  export {
174
94
  GenerateWordPressAssetFileWebpackPlugin
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Inspired by \"Dependency Extraction Webpack Plugin\" by @wordpress team.\n// Link: https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin\nimport { sources, Compilation, Compiler, Chunk } from 'webpack';\n\ntype HandlesMap = {\n\texact: Record<string, string>;\n\tstartsWith: Record<string, string>;\n}\n\ntype Options = {\n\thandlePrefix: string;\n\thandlesMap?: Partial<HandlesMap>\n\tapps?: string[];\n\textensions?: string[];\n\ti18n?: {\n\t\tdomain: string;\n\t\treplaceRequestedFile?: boolean;\n\t}\n}\n\ntype NormalizedOptions = {\n\thandlePrefix: string;\n\thandlesMap: HandlesMap;\n\tapps: string[];\n\textensions: string[];\n\ti18n: {\n\t\tdomain: string | null;\n\t\treplaceRequestedFile: boolean;\n\t}\n}\n\ntype Module = {\n\tuserRequest?: string;\n\tmodules?: Module[];\n}\n\nconst baseHandlesMap: HandlesMap = {\n\texact: {\n\t\treact: 'react',\n\t\t'react-dom': 'react-dom',\n\t},\n\tstartsWith: {\n\t\t'@elementor/': 'elementor-packages-',\n\t\t'@wordpress/': 'wp-',\n\t},\n};\n\nexport class GenerateWordPressAssetFileWebpackPlugin {\n\toptions: NormalizedOptions;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = this.normalizeOptions( options );\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.thisCompilation.tap( this.constructor.name, ( compilation ) => {\n\t\t\tlet handlesAssetsMap: Record<string, string>;\n\n\t\t\tcompilation.hooks.processAssets.tap( { name: this.constructor.name }, () => {\n\t\t\t\thandlesAssetsMap = [ ...compilation.entrypoints ].reduce<Record<string, string>>( ( map, [ entryName, entrypoint ] ) => {\n\t\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === entryName );\n\n\t\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\t\treturn map;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst chunkJSFile = this.getFileFromChunk( chunk );\n\n\t\t\t\t\tif ( ! chunkJSFile ) {\n\t\t\t\t\t\treturn map;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst deps = this.getDepsFromChunk( compilation, chunk );\n\n\t\t\t\t\tconst assetFilename = this.generateAssetsFileName(\n\t\t\t\t\t\tcompilation.getPath( '[file]', { filename: chunkJSFile } )\n\t\t\t\t\t);\n\n\t\t\t\t\tconst handle = this.generateHandleName( entryName );\n\n\t\t\t\t\tconst content = this.createAssetsFileContent( {\n\t\t\t\t\t\tdeps,\n\t\t\t\t\t\tentryName,\n\t\t\t\t\t\ti18n: this.options.i18n,\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Add source and file into compilation for webpack to output.\n\t\t\t\t\tcompilation.assets[ assetFilename ] = new sources.RawSource( content );\n\n\t\t\t\t\tchunk.files.add( assetFilename );\n\n\t\t\t\t\tmap[ handle ] = assetFilename;\n\n\t\t\t\t\treturn map;\n\t\t\t\t}, {} );\n\t\t\t} );\n\n\t\t\tcompilation.hooks.afterProcessAssets.tap( { name: this.constructor.name }, () => {\n\t\t\t\tconst loaderFileContent = this.getLoaderFileContent( handlesAssetsMap );\n\n\t\t\t\tcompilation.assets[ 'loader.php' ] = new sources.RawSource( loaderFileContent );\n\t\t\t} );\n\t\t} );\n\t}\n\n\tgetDepsFromChunk( compilation: Compilation, chunk: Chunk ) {\n\t\tconst depsSet = new Set<string>();\n\n\t\tcompilation.chunkGraph.getChunkModules( chunk ).forEach( ( module ) => {\n\t\t\t// There are some issues with types in webpack, so we need to cast it.\n\t\t\tconst theModule = module as Module;\n\n\t\t\t[ ...( theModule.modules || [] ), theModule ].forEach( ( subModule ) => {\n\t\t\t\tif ( subModule.userRequest && this.isExternalDep( subModule.userRequest ) ) {\n\t\t\t\t\tdepsSet.add( subModule.userRequest );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\treturn depsSet;\n\t}\n\n\tcreateAssetsFileContent( {\n\t\tdeps,\n\t\ti18n,\n\t\tentryName,\n\t}: {\n\t\tdeps: Set<string>;\n\t\ti18n: NormalizedOptions[ 'i18n' ];\n\t\tentryName: string;\n\t} ) {\n\t\tconst handleName = this.generateHandleName( entryName );\n\t\tconst type = this.getEntryType( entryName );\n\n\t\tconst depsAsString = [ ...deps ]\n\t\t\t.map( ( dep ) => this.getHandleFromDep( dep ) )\n\t\t\t.filter( ( dep ) => dep !== handleName )\n\t\t\t.sort()\n\t\t\t.map( ( dep ) => `'${ dep }',` )\n\t\t\t.join( '\\n\\t\\t' );\n\n\t\tconst i18nContent = i18n.domain ? `[\n\t\t'domain' => '${ i18n.domain }',\n\t\t'replace_requested_file' => ${ ( i18n.replaceRequestedFile ?? false ).toString() },\n\t]` : '[]';\n\n\t\tconst content =\n\t\t\t`<?php\nif ( ! defined( 'ABSPATH' ) ) {\n\texit;\n}\n/**\n * This file is generated by Webpack, do not edit it directly.\n */\nreturn [\n\t'handle' => '${ handleName }',\n\t'src' => plugins_url( '/', __FILE__ ) . '${ entryName }{{MIN_SUFFIX}}.js',\n\t'i18n' => ${ i18nContent },\n\t'type' => '${ type }',\n\t'deps' => [\n\t\t${ depsAsString }\n\t],\n];\n`;\n\n\t\treturn content;\n\t}\n\n\tgetLoaderFileContent( entriesData: Record<string, string> ) {\n\t\tconst entriesContent = Object.entries( entriesData ).map( ( [ handle, assetFileName ] ) => {\n\t\t\treturn `\n\t$data['${ handle }'] = require __DIR__ . '/${ assetFileName }';`;\n\t\t} );\n\n\t\treturn `<?php\nif ( ! defined( 'ABSPATH' ) ) {\n\texit;\n}\n/**\n * This file is generated by Webpack, do not edit it directly.\n */\nadd_filter( 'elementor/editor-v2/packages/config', function( $data ) {\n${ entriesContent.join( '\\n' ) }\n\treturn $data;\n} );\n`;\n\t}\n\n\tgetEntryType( entryName: string ) {\n\t\tif ( this.options.extensions.includes( entryName ) ) {\n\t\t\treturn 'extension';\n\t\t}\n\n\t\tif ( this.options.apps.includes( entryName ) ) {\n\t\t\treturn 'app';\n\t\t}\n\n\t\treturn 'util';\n\t}\n\n\tgetFileFromChunk( chunk: Chunk ) {\n\t\treturn [ ...chunk.files ].find( ( f ) => /\\.js$/i.test( f ) );\n\t}\n\n\tisExternalDep( request: string ) {\n\t\tconst { startsWith, exact } = this.options.handlesMap;\n\n\t\treturn request && (\n\t\t\tObject.keys( exact ).includes( request ) ||\n\t\t\tObject.keys( startsWith ).some( ( dep ) => request.startsWith( dep ) )\n\t\t);\n\t}\n\n\tgetHandleFromDep( dep: string ) {\n\t\tconst { startsWith, exact } = this.options.handlesMap;\n\n\t\tif ( Object.keys( exact ).includes( dep ) ) {\n\t\t\treturn exact[ dep ];\n\t\t}\n\n\t\tfor ( const [ key, value ] of Object.entries( startsWith ) ) {\n\t\t\tif ( dep.startsWith( key ) ) {\n\t\t\t\treturn dep.replace( key, value );\n\t\t\t}\n\t\t}\n\n\t\treturn dep;\n\t}\n\n\tgenerateHandleName( name: string ) {\n\t\tif ( this.options.handlePrefix ) {\n\t\t\treturn `${ this.options.handlePrefix }${ name }`;\n\t\t}\n\n\t\treturn name;\n\t}\n\n\tgenerateAssetsFileName( filename: string ) {\n\t\treturn filename.replace( /(\\.min)?\\.js$/i, '.asset.php' );\n\t}\n\n\tnormalizeOptions( options: Options ): NormalizedOptions {\n\t\treturn {\n\t\t\t...options,\n\t\t\thandlesMap: {\n\t\t\t\texact: {\n\t\t\t\t\t...baseHandlesMap.exact,\n\t\t\t\t\t...( options?.handlesMap?.exact || {} ),\n\t\t\t\t},\n\t\t\t\tstartsWith: {\n\t\t\t\t\t...baseHandlesMap.startsWith,\n\t\t\t\t\t...( options?.handlesMap?.startsWith || {} ),\n\t\t\t\t},\n\t\t\t},\n\t\t\tapps: options?.apps || [],\n\t\t\textensions: options?.extensions || [],\n\t\t\ti18n: {\n\t\t\t\tdomain: options?.i18n?.domain || null,\n\t\t\t\treplaceRequestedFile: options?.i18n?.replaceRequestedFile ?? false,\n\t\t\t},\n\t\t};\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/utils.ts"],"sourcesContent":["// Inspired by \"Dependency Extraction Webpack Plugin\" by @wordpress team.\n// Link: https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin\nimport { sources, Compilation, Compiler, Chunk } from 'webpack';\nimport { createAssetFilePath, getAssetFileContent, transformRequestToHandle } from './utils';\nimport { RequestToHandleMap } from './types';\n\ntype Options = {\n\thandle: ( entryName: string ) => string;\n\tmap: RequestToHandleMap\n}\n\ntype Module = {\n\tuserRequest?: string;\n\tmodules?: Module[];\n}\n\nexport default class GenerateWordPressAssetFileWebpackPlugin {\n\toptions: Options;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = options;\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.thisCompilation.tap( this.constructor.name, ( compilation ) => {\n\t\t\tcompilation.hooks.processAssets.tap( { name: this.constructor.name }, () => {\n\t\t\t\t[ ...compilation.entrypoints ].forEach( ( [ entryName, entrypoint ] ) => {\n\t\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === entryName );\n\n\t\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addAssetFileToEntrypoint( compilation, entryName, chunk );\n\t\t\t\t} );\n\t\t\t} );\n\t\t} );\n\t}\n\n\taddAssetFileToEntrypoint( compilation: Compilation, entryName: string, chunk: Chunk ) {\n\t\tconst chunkJSFile = this.getFileFromChunk( chunk );\n\n\t\tif ( ! chunkJSFile ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst transformEntryNameToHandle = this.options.handle;\n\n\t\tconst entryHandle = transformEntryNameToHandle( entryName );\n\t\tconst depsHandles = this.getDepsHandlesFromChunk( compilation, chunk );\n\n\t\tconst assetFilePath = createAssetFilePath(\n\t\t\tcompilation.getPath( '[file]', { filename: chunkJSFile } )\n\t\t);\n\n\t\t// Add source and file into compilation for webpack to output.\n\t\tcompilation.assets[ assetFilePath ] = new sources.RawSource(\n\t\t\tgetAssetFileContent( entryHandle, depsHandles )\n\t\t);\n\n\t\tchunk.files.add( assetFilePath );\n\t}\n\n\tgetDepsHandlesFromChunk( compilation: Compilation, chunk: Chunk ) {\n\t\tconst depsSet = new Set<string>();\n\n\t\tcompilation.chunkGraph.getChunkModules( chunk ).forEach( ( module ) => {\n\t\t\t// There are some issues with types in webpack, so we need to cast it.\n\t\t\tconst theModule = module as Module;\n\n\t\t\t[ ...( theModule.modules || [] ), theModule ].forEach( ( subModule ) => {\n\t\t\t\tconst depHandle = transformRequestToHandle( subModule.userRequest, this.options.map );\n\n\t\t\t\tif ( depHandle ) {\n\t\t\t\t\tdepsSet.add( depHandle );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\treturn [ ...depsSet ];\n\t}\n\n\tgetFileFromChunk( chunk: Chunk ) {\n\t\treturn [ ...chunk.files ].find( ( f ) => /\\.js$/i.test( f ) );\n\t}\n}\n","import { RequestToHandleMap } from './types';\n\nexport function getAssetFileContent( entryHandle: string, depsHandles: string[] ) {\n\tconst depsAsString = depsHandles\n\t\t.filter( ( dep ) => dep !== entryHandle )\n\t\t.sort()\n\t\t.map( ( dep ) => `'${ dep }',` )\n\t\t.join( '\\n\\t\\t' );\n\n\treturn `<?php\nif ( ! defined( 'ABSPATH' ) ) {\n\texit;\n}\n/**\n * This file is generated by Webpack, do not edit it directly.\n */\nreturn [\n\t'handle' => '${ entryHandle }',\n\t'deps' => [\n\t\t${ depsAsString }\n\t],\n];\n`;\n}\n\nexport function transformRequestToHandle( request: string | undefined, map: RequestToHandleMap ) {\n\tif ( ! request ) {\n\t\treturn request;\n\t}\n\n\tfor ( const item of map ) {\n\t\tlet { request: requestRegex, handle } = 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 request.replace( requestRegex, handle );\n\t\t}\n\t}\n}\n\nexport function createAssetFilePath( path: string, suffix = '.asset.php' ) {\n\treturn path.replace( /(\\.min)?\\.js$/i, suffix );\n}\n"],"mappings":";AAEA,SAAS,eAA6C;;;ACA/C,SAAS,oBAAqB,aAAqB,aAAwB;AACjF,QAAM,eAAe,YACnB,OAAQ,CAAE,QAAS,QAAQ,WAAY,EACvC,KAAK,EACL,IAAK,CAAE,QAAS,IAAK,GAAI,IAAK,EAC9B,KAAM,MAAS;AAEjB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAQS,WAAY;AAAA;AAAA,IAExB,YAAa;AAAA;AAAA;AAAA;AAIlB;AAEO,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,QAAQ,QAAS,cAAc,MAAO;AAAA,IAC9C;AAAA,EACD;AACD;AAEO,SAAS,oBAAqB,MAAc,SAAS,cAAe;AAC1E,SAAO,KAAK,QAAS,kBAAkB,MAAO;AAC/C;;;AD/BA,IAAqB,0CAArB,MAA6D;AAAA,EAC5D;AAAA,EAEA,YAAa,SAAmB;AAC/B,SAAK,UAAU;AAAA,EAChB;AAAA,EAEA,MAAO,UAAqB;AAC3B,aAAS,MAAM,gBAAgB,IAAK,KAAK,YAAY,MAAM,CAAE,gBAAiB;AAC7E,kBAAY,MAAM,cAAc,IAAK,EAAE,MAAM,KAAK,YAAY,KAAK,GAAG,MAAM;AAC3E,SAAE,GAAG,YAAY,WAAY,EAAE,QAAS,CAAE,CAAE,WAAW,UAAW,MAAO;AACxE,gBAAM,QAAQ,WAAW,OAAO,KAAM,CAAE,EAAE,KAAK,MAAO,SAAS,SAAU;AAEzE,cAAK,CAAE,OAAQ;AACd;AAAA,UACD;AAEA,eAAK,yBAA0B,aAAa,WAAW,KAAM;AAAA,QAC9D,CAAE;AAAA,MACH,CAAE;AAAA,IACH,CAAE;AAAA,EACH;AAAA,EAEA,yBAA0B,aAA0B,WAAmB,OAAe;AACrF,UAAM,cAAc,KAAK,iBAAkB,KAAM;AAEjD,QAAK,CAAE,aAAc;AACpB;AAAA,IACD;AAEA,UAAM,6BAA6B,KAAK,QAAQ;AAEhD,UAAM,cAAc,2BAA4B,SAAU;AAC1D,UAAM,cAAc,KAAK,wBAAyB,aAAa,KAAM;AAErE,UAAM,gBAAgB;AAAA,MACrB,YAAY,QAAS,UAAU,EAAE,UAAU,YAAY,CAAE;AAAA,IAC1D;AAGA,gBAAY,OAAQ,aAAc,IAAI,IAAI,QAAQ;AAAA,MACjD,oBAAqB,aAAa,WAAY;AAAA,IAC/C;AAEA,UAAM,MAAM,IAAK,aAAc;AAAA,EAChC;AAAA,EAEA,wBAAyB,aAA0B,OAAe;AACjE,UAAM,UAAU,oBAAI,IAAY;AAEhC,gBAAY,WAAW,gBAAiB,KAAM,EAAE,QAAS,CAAE,WAAY;AAEtE,YAAM,YAAY;AAElB,OAAE,GAAK,UAAU,WAAW,CAAC,GAAK,SAAU,EAAE,QAAS,CAAE,cAAe;AACvE,cAAM,YAAY,yBAA0B,UAAU,aAAa,KAAK,QAAQ,GAAI;AAEpF,YAAK,WAAY;AAChB,kBAAQ,IAAK,SAAU;AAAA,QACxB;AAAA,MACD,CAAE;AAAA,IACH,CAAE;AAEF,WAAO,CAAE,GAAG,OAAQ;AAAA,EACrB;AAAA,EAEA,iBAAkB,OAAe;AAChC,WAAO,CAAE,GAAG,MAAM,KAAM,EAAE,KAAM,CAAE,MAAO,SAAS,KAAM,CAAE,CAAE;AAAA,EAC7D;AACD;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/generate-wordpress-asset-file-webpack-plugin",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -34,5 +34,5 @@
34
34
  "peerDependencies": {
35
35
  "webpack": "5.x"
36
36
  },
37
- "gitHead": "0fc79b25b83fa50350f1670cb5d1e31ec8ae0874"
37
+ "gitHead": "7fd9a516887f8bdb3479c54a48dafcb12bb41db7"
38
38
  }
@@ -9,15 +9,11 @@ if ( ! defined( 'ABSPATH' ) ) {
9
9
  * This file is generated by Webpack, do not edit it directly.
10
10
  */
11
11
  return [
12
- 'handle' => 'elementor-test-app',
13
- 'src' => plugins_url( '/', __FILE__ ) . 'app{{MIN_SUFFIX}}.js',
14
- 'i18n' => [
15
- 'domain' => 'elementor-test',
16
- 'replace_requested_file' => true,
17
- ],
18
- 'type' => 'app',
12
+ 'handle' => 'elementor-packages-app',
19
13
  'deps' => [
20
- 'elementor-editor',
14
+ 'elementor-packages-editor',
15
+ 'react',
16
+ 'react-dom',
21
17
  'wp-element',
22
18
  ],
23
19
  ];
@@ -33,41 +29,17 @@ if ( ! defined( 'ABSPATH' ) ) {
33
29
  * This file is generated by Webpack, do not edit it directly.
34
30
  */
35
31
  return [
36
- 'handle' => 'elementor-test-extension',
37
- 'src' => plugins_url( '/', __FILE__ ) . 'extension{{MIN_SUFFIX}}.js',
38
- 'i18n' => [
39
- 'domain' => 'elementor-test',
40
- 'replace_requested_file' => true,
41
- ],
42
- 'type' => 'extension',
32
+ 'handle' => 'elementor-packages-extension',
43
33
  'deps' => [
44
- 'elementor-editor',
34
+ 'elementor-packages-editor',
35
+ 'react',
36
+ 'react-dom',
45
37
  'wp-element',
46
38
  ],
47
39
  ];
48
40
  "
49
41
  `;
50
42
 
51
- exports[`@elementor/generate-wordpress-asset-file-webpack-plugin should generate assets files: loader.php 1`] = `
52
- "<?php
53
- if ( ! defined( 'ABSPATH' ) ) {
54
- exit;
55
- }
56
- /**
57
- * This file is generated by Webpack, do not edit it directly.
58
- */
59
- add_filter( 'elementor/editor-v2/packages/config', function( $data ) {
60
-
61
- $data['elementor-test-app'] = require __DIR__ . '/app.asset.php';
62
-
63
- $data['elementor-test-extension'] = require __DIR__ . '/extension.asset.php';
64
-
65
- $data['elementor-test-util'] = require __DIR__ . '/util.asset.php';
66
- return $data;
67
- } );
68
- "
69
- `;
70
-
71
43
  exports[`@elementor/generate-wordpress-asset-file-webpack-plugin should generate assets files: util.asset.php 1`] = `
72
44
  "<?php
73
45
  if ( ! defined( 'ABSPATH' ) ) {
@@ -77,15 +49,11 @@ if ( ! defined( 'ABSPATH' ) ) {
77
49
  * This file is generated by Webpack, do not edit it directly.
78
50
  */
79
51
  return [
80
- 'handle' => 'elementor-test-util',
81
- 'src' => plugins_url( '/', __FILE__ ) . 'util{{MIN_SUFFIX}}.js',
82
- 'i18n' => [
83
- 'domain' => 'elementor-test',
84
- 'replace_requested_file' => true,
85
- ],
86
- 'type' => 'util',
52
+ 'handle' => 'elementor-packages-util',
87
53
  'deps' => [
88
- 'elementor-editor',
54
+ 'elementor-packages-editor',
55
+ 'react',
56
+ 'react-dom',
89
57
  'wp-element',
90
58
  ],
91
59
  ];
@@ -16,6 +16,8 @@ describe( '@elementor/generate-wordpress-asset-file-webpack-plugin', () => {
16
16
  import elementor from '@elementor/editor';
17
17
  import wp from '@wordpress/element';
18
18
  import other from '@other/package';
19
+ import react from 'react';
20
+ import ReactDOM from 'react-dom';
19
21
 
20
22
  elementor();
21
23
  wp();
@@ -49,30 +51,24 @@ describe( '@elementor/generate-wordpress-asset-file-webpack-plugin', () => {
49
51
  '@elementor/editor': 'editor',
50
52
  '@wordpress/element': 'wp',
51
53
  '@other/package': 'other',
54
+ react: 'react',
55
+ 'react-dom': 'reactDOM',
52
56
  },
53
57
  plugins: [
54
58
  new GenerateWordPressAssetFileWebpackPlugin( {
55
- handlePrefix: 'elementor-test-',
56
- apps: [ 'app' ],
57
- extensions: [ 'extension' ],
58
- handlesMap: {
59
- exact: {
60
- '@elementor/editor': 'elementor-editor',
61
- },
62
- startsWith: {
63
- '@wordpress/': 'wp-',
64
- },
65
- },
66
- i18n: {
67
- domain: 'elementor-test',
68
- replaceRequestedFile: true,
69
- },
59
+ handle: ( entryName ) => `elementor-packages-${ entryName }`,
60
+ map: [
61
+ { request: 'react', handle: 'react' },
62
+ { request: 'react-dom', handle: 'react-dom' },
63
+ { request: /^@elementor\/(.+)$/, handle: 'elementor-packages-$1' },
64
+ { request: /^@wordpress\/(.+)$/, handle: 'wp-$1' },
65
+ ],
70
66
  } ),
71
67
  ],
72
68
  } );
73
69
 
74
70
  // Expect.
75
- expect.assertions( 7 );
71
+ expect.assertions( 6 );
76
72
 
77
73
  // Act.
78
74
  compiler.run( ( err, stats ) => {
@@ -85,7 +81,6 @@ describe( '@elementor/generate-wordpress-asset-file-webpack-plugin', () => {
85
81
  'app.asset.php',
86
82
  'extension.asset.php',
87
83
  'util.asset.php',
88
- 'loader.php',
89
84
  ];
90
85
 
91
86
  files.forEach( ( fileName ) => {
package/src/index.ts CHANGED
@@ -1,263 +1 @@
1
- // Inspired by "Dependency Extraction Webpack Plugin" by @wordpress team.
2
- // Link: https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin
3
- import { sources, Compilation, Compiler, Chunk } from 'webpack';
4
-
5
- type HandlesMap = {
6
- exact: Record<string, string>;
7
- startsWith: Record<string, string>;
8
- }
9
-
10
- type Options = {
11
- handlePrefix: string;
12
- handlesMap?: Partial<HandlesMap>
13
- apps?: string[];
14
- extensions?: string[];
15
- i18n?: {
16
- domain: string;
17
- replaceRequestedFile?: boolean;
18
- }
19
- }
20
-
21
- type NormalizedOptions = {
22
- handlePrefix: string;
23
- handlesMap: HandlesMap;
24
- apps: string[];
25
- extensions: string[];
26
- i18n: {
27
- domain: string | null;
28
- replaceRequestedFile: boolean;
29
- }
30
- }
31
-
32
- type Module = {
33
- userRequest?: string;
34
- modules?: Module[];
35
- }
36
-
37
- const baseHandlesMap: HandlesMap = {
38
- exact: {
39
- react: 'react',
40
- 'react-dom': 'react-dom',
41
- },
42
- startsWith: {
43
- '@elementor/': 'elementor-packages-',
44
- '@wordpress/': 'wp-',
45
- },
46
- };
47
-
48
- export class GenerateWordPressAssetFileWebpackPlugin {
49
- options: NormalizedOptions;
50
-
51
- constructor( options: Options ) {
52
- this.options = this.normalizeOptions( options );
53
- }
54
-
55
- apply( compiler: Compiler ) {
56
- compiler.hooks.thisCompilation.tap( this.constructor.name, ( compilation ) => {
57
- let handlesAssetsMap: Record<string, string>;
58
-
59
- compilation.hooks.processAssets.tap( { name: this.constructor.name }, () => {
60
- handlesAssetsMap = [ ...compilation.entrypoints ].reduce<Record<string, string>>( ( map, [ entryName, entrypoint ] ) => {
61
- const chunk = entrypoint.chunks.find( ( { name } ) => name === entryName );
62
-
63
- if ( ! chunk ) {
64
- return map;
65
- }
66
-
67
- const chunkJSFile = this.getFileFromChunk( chunk );
68
-
69
- if ( ! chunkJSFile ) {
70
- return map;
71
- }
72
-
73
- const deps = this.getDepsFromChunk( compilation, chunk );
74
-
75
- const assetFilename = this.generateAssetsFileName(
76
- compilation.getPath( '[file]', { filename: chunkJSFile } )
77
- );
78
-
79
- const handle = this.generateHandleName( entryName );
80
-
81
- const content = this.createAssetsFileContent( {
82
- deps,
83
- entryName,
84
- i18n: this.options.i18n,
85
- } );
86
-
87
- // Add source and file into compilation for webpack to output.
88
- compilation.assets[ assetFilename ] = new sources.RawSource( content );
89
-
90
- chunk.files.add( assetFilename );
91
-
92
- map[ handle ] = assetFilename;
93
-
94
- return map;
95
- }, {} );
96
- } );
97
-
98
- compilation.hooks.afterProcessAssets.tap( { name: this.constructor.name }, () => {
99
- const loaderFileContent = this.getLoaderFileContent( handlesAssetsMap );
100
-
101
- compilation.assets[ 'loader.php' ] = new sources.RawSource( loaderFileContent );
102
- } );
103
- } );
104
- }
105
-
106
- getDepsFromChunk( compilation: Compilation, chunk: Chunk ) {
107
- const depsSet = new Set<string>();
108
-
109
- compilation.chunkGraph.getChunkModules( chunk ).forEach( ( module ) => {
110
- // There are some issues with types in webpack, so we need to cast it.
111
- const theModule = module as Module;
112
-
113
- [ ...( theModule.modules || [] ), theModule ].forEach( ( subModule ) => {
114
- if ( subModule.userRequest && this.isExternalDep( subModule.userRequest ) ) {
115
- depsSet.add( subModule.userRequest );
116
- }
117
- } );
118
- } );
119
-
120
- return depsSet;
121
- }
122
-
123
- createAssetsFileContent( {
124
- deps,
125
- i18n,
126
- entryName,
127
- }: {
128
- deps: Set<string>;
129
- i18n: NormalizedOptions[ 'i18n' ];
130
- entryName: string;
131
- } ) {
132
- const handleName = this.generateHandleName( entryName );
133
- const type = this.getEntryType( entryName );
134
-
135
- const depsAsString = [ ...deps ]
136
- .map( ( dep ) => this.getHandleFromDep( dep ) )
137
- .filter( ( dep ) => dep !== handleName )
138
- .sort()
139
- .map( ( dep ) => `'${ dep }',` )
140
- .join( '\n\t\t' );
141
-
142
- const i18nContent = i18n.domain ? `[
143
- 'domain' => '${ i18n.domain }',
144
- 'replace_requested_file' => ${ ( i18n.replaceRequestedFile ?? false ).toString() },
145
- ]` : '[]';
146
-
147
- const content =
148
- `<?php
149
- if ( ! defined( 'ABSPATH' ) ) {
150
- exit;
151
- }
152
- /**
153
- * This file is generated by Webpack, do not edit it directly.
154
- */
155
- return [
156
- 'handle' => '${ handleName }',
157
- 'src' => plugins_url( '/', __FILE__ ) . '${ entryName }{{MIN_SUFFIX}}.js',
158
- 'i18n' => ${ i18nContent },
159
- 'type' => '${ type }',
160
- 'deps' => [
161
- ${ depsAsString }
162
- ],
163
- ];
164
- `;
165
-
166
- return content;
167
- }
168
-
169
- getLoaderFileContent( entriesData: Record<string, string> ) {
170
- const entriesContent = Object.entries( entriesData ).map( ( [ handle, assetFileName ] ) => {
171
- return `
172
- $data['${ handle }'] = require __DIR__ . '/${ assetFileName }';`;
173
- } );
174
-
175
- return `<?php
176
- if ( ! defined( 'ABSPATH' ) ) {
177
- exit;
178
- }
179
- /**
180
- * This file is generated by Webpack, do not edit it directly.
181
- */
182
- add_filter( 'elementor/editor-v2/packages/config', function( $data ) {
183
- ${ entriesContent.join( '\n' ) }
184
- return $data;
185
- } );
186
- `;
187
- }
188
-
189
- getEntryType( entryName: string ) {
190
- if ( this.options.extensions.includes( entryName ) ) {
191
- return 'extension';
192
- }
193
-
194
- if ( this.options.apps.includes( entryName ) ) {
195
- return 'app';
196
- }
197
-
198
- return 'util';
199
- }
200
-
201
- getFileFromChunk( chunk: Chunk ) {
202
- return [ ...chunk.files ].find( ( f ) => /\.js$/i.test( f ) );
203
- }
204
-
205
- isExternalDep( request: string ) {
206
- const { startsWith, exact } = this.options.handlesMap;
207
-
208
- return request && (
209
- Object.keys( exact ).includes( request ) ||
210
- Object.keys( startsWith ).some( ( dep ) => request.startsWith( dep ) )
211
- );
212
- }
213
-
214
- getHandleFromDep( dep: string ) {
215
- const { startsWith, exact } = this.options.handlesMap;
216
-
217
- if ( Object.keys( exact ).includes( dep ) ) {
218
- return exact[ dep ];
219
- }
220
-
221
- for ( const [ key, value ] of Object.entries( startsWith ) ) {
222
- if ( dep.startsWith( key ) ) {
223
- return dep.replace( key, value );
224
- }
225
- }
226
-
227
- return dep;
228
- }
229
-
230
- generateHandleName( name: string ) {
231
- if ( this.options.handlePrefix ) {
232
- return `${ this.options.handlePrefix }${ name }`;
233
- }
234
-
235
- return name;
236
- }
237
-
238
- generateAssetsFileName( filename: string ) {
239
- return filename.replace( /(\.min)?\.js$/i, '.asset.php' );
240
- }
241
-
242
- normalizeOptions( options: Options ): NormalizedOptions {
243
- return {
244
- ...options,
245
- handlesMap: {
246
- exact: {
247
- ...baseHandlesMap.exact,
248
- ...( options?.handlesMap?.exact || {} ),
249
- },
250
- startsWith: {
251
- ...baseHandlesMap.startsWith,
252
- ...( options?.handlesMap?.startsWith || {} ),
253
- },
254
- },
255
- apps: options?.apps || [],
256
- extensions: options?.extensions || [],
257
- i18n: {
258
- domain: options?.i18n?.domain || null,
259
- replaceRequestedFile: options?.i18n?.replaceRequestedFile ?? false,
260
- },
261
- };
262
- }
263
- }
1
+ export { default as GenerateWordPressAssetFileWebpackPlugin } from './plugin';
package/src/plugin.ts ADDED
@@ -0,0 +1,86 @@
1
+ // Inspired by "Dependency Extraction Webpack Plugin" by @wordpress team.
2
+ // Link: https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin
3
+ import { sources, Compilation, Compiler, Chunk } from 'webpack';
4
+ import { createAssetFilePath, getAssetFileContent, transformRequestToHandle } from './utils';
5
+ import { RequestToHandleMap } from './types';
6
+
7
+ type Options = {
8
+ handle: ( entryName: string ) => string;
9
+ map: RequestToHandleMap
10
+ }
11
+
12
+ type Module = {
13
+ userRequest?: string;
14
+ modules?: Module[];
15
+ }
16
+
17
+ export default class GenerateWordPressAssetFileWebpackPlugin {
18
+ options: Options;
19
+
20
+ constructor( options: Options ) {
21
+ this.options = options;
22
+ }
23
+
24
+ apply( compiler: Compiler ) {
25
+ compiler.hooks.thisCompilation.tap( this.constructor.name, ( compilation ) => {
26
+ compilation.hooks.processAssets.tap( { name: this.constructor.name }, () => {
27
+ [ ...compilation.entrypoints ].forEach( ( [ entryName, entrypoint ] ) => {
28
+ const chunk = entrypoint.chunks.find( ( { name } ) => name === entryName );
29
+
30
+ if ( ! chunk ) {
31
+ return;
32
+ }
33
+
34
+ this.addAssetFileToEntrypoint( compilation, entryName, chunk );
35
+ } );
36
+ } );
37
+ } );
38
+ }
39
+
40
+ addAssetFileToEntrypoint( compilation: Compilation, entryName: string, chunk: Chunk ) {
41
+ const chunkJSFile = this.getFileFromChunk( chunk );
42
+
43
+ if ( ! chunkJSFile ) {
44
+ return;
45
+ }
46
+
47
+ const transformEntryNameToHandle = this.options.handle;
48
+
49
+ const entryHandle = transformEntryNameToHandle( entryName );
50
+ const depsHandles = this.getDepsHandlesFromChunk( compilation, chunk );
51
+
52
+ const assetFilePath = createAssetFilePath(
53
+ compilation.getPath( '[file]', { filename: chunkJSFile } )
54
+ );
55
+
56
+ // Add source and file into compilation for webpack to output.
57
+ compilation.assets[ assetFilePath ] = new sources.RawSource(
58
+ getAssetFileContent( entryHandle, depsHandles )
59
+ );
60
+
61
+ chunk.files.add( assetFilePath );
62
+ }
63
+
64
+ getDepsHandlesFromChunk( compilation: Compilation, chunk: Chunk ) {
65
+ const depsSet = new Set<string>();
66
+
67
+ compilation.chunkGraph.getChunkModules( chunk ).forEach( ( module ) => {
68
+ // There are some issues with types in webpack, so we need to cast it.
69
+ const theModule = module as Module;
70
+
71
+ [ ...( theModule.modules || [] ), theModule ].forEach( ( subModule ) => {
72
+ const depHandle = transformRequestToHandle( subModule.userRequest, this.options.map );
73
+
74
+ if ( depHandle ) {
75
+ depsSet.add( depHandle );
76
+ }
77
+ } );
78
+ } );
79
+
80
+ return [ ...depsSet ];
81
+ }
82
+
83
+ getFileFromChunk( chunk: Chunk ) {
84
+ return [ ...chunk.files ].find( ( f ) => /\.js$/i.test( f ) );
85
+ }
86
+ }
package/src/types.ts ADDED
@@ -0,0 +1,4 @@
1
+ export type RequestToHandleMap = Array<{
2
+ request: string | RegExp,
3
+ handle: string
4
+ }>
package/src/utils.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { RequestToHandleMap } from './types';
2
+
3
+ export function getAssetFileContent( entryHandle: string, depsHandles: string[] ) {
4
+ const depsAsString = depsHandles
5
+ .filter( ( dep ) => dep !== entryHandle )
6
+ .sort()
7
+ .map( ( dep ) => `'${ dep }',` )
8
+ .join( '\n\t\t' );
9
+
10
+ return `<?php
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ exit;
13
+ }
14
+ /**
15
+ * This file is generated by Webpack, do not edit it directly.
16
+ */
17
+ return [
18
+ 'handle' => '${ entryHandle }',
19
+ 'deps' => [
20
+ ${ depsAsString }
21
+ ],
22
+ ];
23
+ `;
24
+ }
25
+
26
+ export function transformRequestToHandle( request: string | undefined, map: RequestToHandleMap ) {
27
+ if ( ! request ) {
28
+ return request;
29
+ }
30
+
31
+ for ( const item of map ) {
32
+ let { request: requestRegex, handle } = item;
33
+
34
+ if ( ! ( requestRegex instanceof RegExp ) ) {
35
+ requestRegex = new RegExp( `^${ requestRegex }$` );
36
+ }
37
+
38
+ const matches = request.match( requestRegex );
39
+
40
+ if ( matches ) {
41
+ return request.replace( requestRegex, handle );
42
+ }
43
+ }
44
+ }
45
+
46
+ export function createAssetFilePath( path: string, suffix = '.asset.php' ) {
47
+ return path.replace( /(\.min)?\.js$/i, suffix );
48
+ }