Skip to content

Commit 2212272

Browse files
committed
feat: initial code for organizing polyfill plugins
1 parent 2fc4ba0 commit 2212272

File tree

20 files changed

+718
-472
lines changed

20 files changed

+718
-472
lines changed

lib/build/bundlers/bundler-base.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import merge from 'lodash.merge';
2+
3+
// TODO: insert docs, test
4+
/**
5+
* BundlerBase
6+
*/
7+
class BundlerBase {
8+
constructor(builderConfig) {
9+
this.builderConfig = builderConfig;
10+
this.customConfigPreset = builderConfig.custom;
11+
this.customConfigLocal = builderConfig.localCustom;
12+
}
13+
14+
// eslint-disable-next-line class-methods-use-this
15+
async run() {
16+
// Implement plugin modification logic here
17+
// This method can be overridden by subclasses
18+
}
19+
20+
mergeConfig = (config = {}) => {
21+
let mergeConfig = { ...config };
22+
const hasCustomConfig = Object.keys(this.customConfigPreset).length > 0;
23+
const hasCustomConfigLocal = Object.keys(this.customConfigLocal).length > 0;
24+
if (hasCustomConfig || hasCustomConfigLocal) {
25+
mergeConfig = merge(
26+
mergeConfig,
27+
this.customConfigPreset,
28+
this.customConfigLocal,
29+
);
30+
}
31+
return mergeConfig;
32+
};
33+
34+
// eslint-disable-next-line class-methods-use-this
35+
applyConfig() {
36+
throw new Error('please implement this config');
37+
}
38+
}
39+
40+
export default BundlerBase;

lib/build/bundlers/esbuild/esbuild.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const outputPath = isWindows
99

1010
export default {
1111
bundle: true,
12-
minify: true,
12+
minify: false,
1313
target: 'es2022',
1414
platform: 'browser',
1515
loader: {

lib/build/bundlers/esbuild/index.js

+26-23
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,62 @@
11
import * as esbuild from 'esbuild';
2-
import merge from 'deepmerge';
32

43
import { debug } from '#utils';
54
import { Messages } from '#constants';
65

76
import AzionEsbuildConfig from './esbuild.config.js';
87
import { NodeModulesPolyfillPlugin } from './plugins/node-polyfills/index.js';
8+
import BundlerBase from '../bundler-base.js';
99

10-
class Esbuild {
10+
class Esbuild extends BundlerBase {
11+
// eslint-disable-next-line no-useless-constructor
1112
constructor(builderConfig) {
12-
this.builderConfig = builderConfig;
13-
this.customConfigPreset = builderConfig.custom;
14-
this.customConfigLocal = builderConfig.localCustom;
13+
super(builderConfig);
1514
}
1615

17-
run = async () => {
16+
async run() {
1817
let config = AzionEsbuildConfig;
1918
config.entryPoints = [this.builderConfig.entry];
2019
config.define = {
2120
AZION_VERSION_ID: JSON.stringify(this.builderConfig.buildId),
2221
};
2322

24-
const hasCustomConfig = Object.keys(this.customConfigPreset).length > 0;
25-
if (hasCustomConfig) {
26-
config = merge(this.customConfigPreset, this.customConfigLocal, config);
23+
config = super.mergeConfig(config);
24+
config = this.applyConfig(config);
25+
26+
try {
27+
await esbuild.build(config);
28+
} catch (error) {
29+
debug.error(error);
30+
throw Error(Messages.build.error.vulcan_build_failed);
2731
}
32+
}
2833

34+
async applyConfig(config) {
35+
const modifyConfig = { ...config };
2936
if (
3037
this.builderConfig.useNodePolyfills ||
3138
this.customConfigPreset.useNodePolyfills ||
3239
this.customConfigLocal
3340
) {
34-
if (!config.plugins) config.plugins = [];
35-
36-
config.plugins = [NodeModulesPolyfillPlugin(), ...config.plugins];
41+
if (!modifyConfig.plugins) modifyConfig.plugins = [];
42+
modifyConfig.plugins = [
43+
NodeModulesPolyfillPlugin(),
44+
...modifyConfig.plugins,
45+
];
3746
}
3847

3948
// inject content in worker initial code.
4049
if (this.builderConfig.contentToInject) {
4150
const workerInitContent = this.builderConfig.contentToInject;
4251

43-
if (config.banner?.js) {
44-
config.banner.js = `${config.banner.js} ${workerInitContent}`;
52+
if (modifyConfig.banner?.js) {
53+
modifyConfig.banner.js = `${modifyConfig.banner.js} ${workerInitContent}`;
4554
} else {
46-
config.banner = { js: workerInitContent };
55+
modifyConfig.banner = { js: workerInitContent };
4756
}
4857
}
49-
50-
try {
51-
await esbuild.build(config);
52-
} catch (error) {
53-
debug.error(error);
54-
throw Error(Messages.build.error.vulcan_build_failed);
55-
}
56-
};
58+
return modifyConfig;
59+
}
5760
}
5861

5962
export default Esbuild;

lib/build/bundlers/esbuild/plugins/node-polyfills/index.js

+58-33
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
/* eslint-disable */
2-
// Based on https://github.com/remorses/esbuild-plugins/blob/master/node-modules-polyfill/src/index.ts
3-
1+
/* eslint-disable no-param-reassign */
2+
import escapeStringRegexp from 'escape-string-regexp';
43
import fs from 'fs';
54
import path from 'path';
65

7-
import builtinsPolyfills from './node-polyfills-paths.js';
6+
import builtinsPolyfills from '../../../polyfills/node-polyfills-paths.js';
87

9-
const NAME = 'node-modules-polyfills';
8+
const NAME = 'vulcan-node-modules-polyfills';
109
const NAMESPACE = NAME;
1110

1211
/**
@@ -22,35 +21,23 @@ function removeEndingSlash(importee) {
2221
return importee;
2322
}
2423

25-
function escapeStringRegexp(string) {
26-
if (typeof string !== 'string') {
27-
throw new TypeError('Expected a string');
28-
}
29-
30-
// Escape characters with special meaning either inside or outside character sets.
31-
// Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
32-
return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d');
33-
}
34-
3524
/**
3625
* Generates a template for commonjs with module require
3726
* @param {string} importPath - the import path
3827
* @returns {string} the template
3928
*/
4029
function commonJsTemplate({ importPath }) {
4130
return `
42-
const polyfill = require('${importPath}')
31+
const polyfill = require('${importPath}')
4332
44-
if (polyfill && polyfill.default) {
45-
module.exports = polyfill.default
46-
for (let k in polyfill) {
47-
module.exports[k] = polyfill[k]
33+
if (polyfill && polyfill.default) {
34+
module.exports = polyfill.default
35+
for (let k in polyfill) {
36+
module.exports[k] = polyfill[k]
37+
}
38+
} else if (polyfill) {
39+
module.exports = polyfill
4840
}
49-
} else if (polyfill) {
50-
module.exports = polyfill
51-
}
52-
53-
5441
`;
5542
}
5643

@@ -68,7 +55,7 @@ export function NodeModulesPolyfillPlugin(options = {}) {
6855
// require('assert') will give you import('assert').default
6956
const commonjsNamespace = `${namespace}-commonjs`;
7057
const polyfilledBuiltins = builtinsPolyfills();
71-
const polyfilledBuiltinsNames = [...polyfilledBuiltins.keys()];
58+
const polyfilledBuiltinsNames = [...polyfilledBuiltins.libs.keys()];
7259

7360
return {
7461
name,
@@ -77,10 +64,31 @@ export function NodeModulesPolyfillPlugin(options = {}) {
7764
if (initialOptions?.define && !initialOptions.define?.global) {
7865
initialOptions.define.global = 'globalThis';
7966
} else if (!initialOptions?.define) {
80-
initialOptions.define = { global: 'globalThis' };
67+
initialOptions.define = {
68+
global: 'globalThis',
69+
};
70+
}
71+
if (initialOptions.external && initialOptions.external.length > 0) {
72+
const changedExternal = initialOptions.external.reduce(
73+
(acc, current) => {
74+
if (polyfilledBuiltinsNames.includes(current)) {
75+
acc[`node:${current}`] = current;
76+
}
77+
acc[current] = current;
78+
return acc;
79+
},
80+
{},
81+
);
82+
initialOptions.external = Object.keys(changedExternal);
83+
}
84+
initialOptions.inject = initialOptions.inject || [];
85+
86+
if (polyfilledBuiltins.globals) {
87+
[...polyfilledBuiltins.globals].forEach(([, value]) => {
88+
initialOptions.inject.push(value);
89+
});
8190
}
8291

83-
// TODO these polyfill module cannot import anything, is that ok?
8492
/**
8593
*
8694
* @param args
@@ -90,12 +98,16 @@ export function NodeModulesPolyfillPlugin(options = {}) {
9098
const argsPath = args.path.replace(/^node:/, '');
9199
const isCommonjs = args.namespace.endsWith('commonjs');
92100

93-
const resolved = polyfilledBuiltins.get(removeEndingSlash(argsPath));
101+
const resolved = polyfilledBuiltins.libs.get(
102+
removeEndingSlash(argsPath),
103+
);
94104
const contents = await (
95105
await fs.promises.readFile(resolved)
96106
).toString();
97107
const resolveDir = path.dirname(resolved);
98108

109+
const modifiedContents = contents.replace(/node:/g, '');
110+
99111
if (isCommonjs) {
100112
return {
101113
loader: 'js',
@@ -107,7 +119,7 @@ export function NodeModulesPolyfillPlugin(options = {}) {
107119
}
108120
return {
109121
loader: 'js',
110-
contents,
122+
contents: modifiedContents,
111123
resolveDir,
112124
};
113125
} catch (e) {
@@ -118,8 +130,10 @@ export function NodeModulesPolyfillPlugin(options = {}) {
118130
};
119131
}
120132
}
133+
121134
onLoad({ filter: /.*/, namespace }, loader);
122135
onLoad({ filter: /.*/, namespace: commonjsNamespace }, loader);
136+
123137
const filter = new RegExp(
124138
[
125139
...polyfilledBuiltinsNames,
@@ -129,26 +143,37 @@ export function NodeModulesPolyfillPlugin(options = {}) {
129143
.join('|'), // TODO builtins could end with slash, keep in mind in regex
130144
);
131145

146+
/**
147+
*
148+
* @param args
149+
*/
132150
async function resolver(args) {
133151
const argsPath = args.path.replace(/^node:/, '');
134152
const ignoreRequire = args.namespace === commonjsNamespace;
153+
const isCommonjs = !ignoreRequire && args.kind === 'require-call';
135154

136-
if (!polyfilledBuiltins.has(argsPath)) {
155+
if (!polyfilledBuiltins.libs.has(argsPath)) {
137156
return;
138157
}
139158

140-
const isCommonjs = !ignoreRequire && args.kind === 'require-call';
159+
if (
160+
initialOptions.external &&
161+
initialOptions.external.includes(args.path)
162+
) {
163+
return;
164+
}
141165

166+
// eslint-disable-next-line consistent-return
142167
return {
143168
namespace: isCommonjs ? commonjsNamespace : namespace,
144169
path: argsPath,
145170
};
146171
}
147172
onResolve({ filter }, resolver);
173+
148174
// onResolve({ filter: /.*/, namespace }, resolver)
149175
},
150176
};
151177
}
152178

153179
export default NodeModulesPolyfillPlugin;
154-
/* eslint-enable */

0 commit comments

Comments
 (0)