Skip to content

Commit 52bcd13

Browse files
committed
feat: added building with external api to local runtime
1 parent a44dbb0 commit 52bcd13

File tree

11 files changed

+128
-10
lines changed

11 files changed

+128
-10
lines changed

lib/build/bundlers/esbuild/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class Esbuild extends BundlerBase {
5252

5353
if (useNodePolyfills) {
5454
if (!updatedConfig.plugins) updatedConfig.plugins = [];
55-
updatedConfig.plugins.push(ESBuildNodeModulePlugin());
55+
updatedConfig.plugins.push(ESBuildNodeModulePlugin(globalThis.buildProd));
5656
}
5757

5858
// inject content in worker initial code.

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

+25-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import path from 'path';
44
import PolyfillsManager from '../../../polyfills/polyfills-manager.js';
55

66
/**
7+
* @param {boolean} buildProd Parameter to identify whether the build is dev or prod
78
* ESBuild Node Module Plugin for polyfilling node modules.
89
* @returns {object} - ESBuild plugin object.
910
*/
10-
const ESBuildNodeModulePlugin = () => {
11+
const ESBuildNodeModulePlugin = (buildProd) => {
1112
const NAME = 'vulcan-node-modules-polyfills';
1213
const NAMESPACE = NAME;
1314

@@ -43,13 +44,30 @@ const ESBuildNodeModulePlugin = () => {
4344
});
4445
}
4546

47+
// external
48+
if (buildProd) {
49+
options.external = options.external || [];
50+
[...polyfillManager.external].forEach(([key]) => {
51+
options.external.push(key);
52+
options.external.push(`node:${key}`);
53+
});
54+
}
55+
4656
/**
4757
* Resolve callback for ESBuild.
4858
* @param {object} args - Arguments object.
4959
* @returns {object|undefined} - Object with path and namespace or undefined.
5060
*/
5161
build.onResolve({ filter: /.*/ }, async (args) => {
5262
const argsPath = args.path.replace(/^node:/, '');
63+
64+
if (!buildProd && polyfillManager.external.has(argsPath)) {
65+
return {
66+
path: args.path,
67+
namespace: NAMESPACE,
68+
};
69+
}
70+
5371
if (!polyfillManager.libs.has(argsPath)) {
5472
return;
5573
}
@@ -98,7 +116,12 @@ const ESBuildNodeModulePlugin = () => {
98116
build.onLoad({ filter: /.*/, namespace: NAMESPACE }, async (args) => {
99117
const argsPath = args.path.replace(/^node:/, '');
100118

101-
const resolved = polyfillManager.libs.get(argsPath);
119+
let resolved = polyfillManager.libs.get(argsPath);
120+
121+
if (!buildProd && polyfillManager.external.has(argsPath)) {
122+
resolved = polyfillManager.external.get(argsPath);
123+
}
124+
102125
const contents = await fs.promises.readFile(resolved, 'utf8');
103126
const resolveDir = path.dirname(resolved);
104127

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* eslint-disable */
2+
export class AsyncLocalStorage {
3+
constructor() {
4+
this.store = new Map();
5+
}
6+
7+
run(storeData, callback) {
8+
const key = Symbol();
9+
this.store.set(key, storeData);
10+
const restoreData = Object.fromEntries(this.store);
11+
12+
return callback(restoreData);
13+
}
14+
15+
getStore() {
16+
const allEntries = [...this.store.entries()];
17+
if (allEntries.length === 0) return undefined;
18+
19+
const [_, lastValue] = allEntries[allEntries.length - 1];
20+
return lastValue;
21+
}
22+
23+
enterWith(storeData) {
24+
this.store = new Map(Object.entries(storeData));
25+
}
26+
27+
exit() {
28+
this.store = new Map();
29+
}
30+
}
31+
32+
export default {
33+
AsyncLocalStorage,
34+
};

lib/build/bundlers/polyfills/polyfills-manager.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class PolyfillsManager {
2121
this.libs = new Map();
2222
/** @type {Map<string, string|boolean>} */
2323
this.alias = new Map();
24+
/** @type {Map<string, string|boolean>} */
25+
this.external = new Map();
2426
}
2527

2628
/**
@@ -50,9 +52,18 @@ class PolyfillsManager {
5052
this.alias.set(name, path);
5153
}
5254

55+
/**
56+
* Sets a external libs.
57+
* @param {string} name - Name of the external.
58+
* @param {string|boolean} path - Path to the polyfill or a boolean value.
59+
*/
60+
setExternal(name, path) {
61+
this.external.set(name, path);
62+
}
63+
5364
/**
5465
* Builds and retrieves the polyfills for Node and globals.
55-
* @returns {{ libs: Map<string, string|boolean>, globals: Map<string, string>, alias: Map<string, string> }} - Object containing libs and globals.
66+
* @returns {{ libs: Map<string, string|boolean>, globals: Map<string, string>, alias: Map<string, string>, external: Map<string, string> }} - Object containing libs and globals.
5667
*/
5768
buildPolyfills() {
5869
this.setGlobal('buffer', `${nodePolyfillsPath}/globals/buffer.js`);
@@ -70,7 +81,6 @@ class PolyfillsManager {
7081
);
7182

7283
this.setLib('accepts', require.resolve('accepts'));
73-
this.setLib('async_hooks', `${nodePolyfillsPath}/_empty.js`);
7484
this.setLib('buffer', require.resolve('buffer/'));
7585
this.setLib('child_process', `${nodePolyfillsPath}/_empty.js`);
7686
this.setLib('cluster', `${nodePolyfillsPath}/_empty.js`);
@@ -131,7 +141,14 @@ class PolyfillsManager {
131141
this.setAlias('util', require.resolve('util/'));
132142
this.setAlias('process', `${nodePolyfillsPath}/globals/process.js`);
133143

134-
return { libs: this.libs, globals: this.globals, alias: this.alias };
144+
this.setExternal('async_hooks', `${nodePolyfillsPath}/async_hooks.js`);
145+
146+
return {
147+
libs: this.libs,
148+
globals: this.globals,
149+
alias: this.alias,
150+
external: this.external,
151+
};
135152
}
136153
}
137154

lib/build/bundlers/polyfills/polyfills-manager.test.js

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ describe('Polyfills Manager', () => {
55
it('Should return map of polyfills', () => {
66
const expectedPolyfills = [
77
'accepts',
8-
'async_hooks',
98
'buffer',
109
'child_process',
1110
'cluster',

lib/build/bundlers/webpack/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class Webpack extends BundlerBase {
8787
this.presetMode === 'compute';
8888

8989
if (useNodePolyfills) {
90-
updatedConfig.plugins.push(new NodePolyfillPlugin());
90+
updatedConfig.plugins.push(new NodePolyfillPlugin(globalThis.buildProd));
9191
}
9292
return updatedConfig;
9393
}

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

+26
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { generateWebpackBanner } from '#utils';
33
import PolyfillsManager from '../../../polyfills/polyfills-manager.js';
44

55
class NodePolyfillPlugin {
6+
constructor(buildProd) {
7+
this.buildProd = buildProd;
8+
}
9+
610
apply(compiler) {
711
const polyfillsManager = PolyfillsManager.buildPolyfills();
812

@@ -46,6 +50,28 @@ class NodePolyfillPlugin {
4650
}),
4751
);
4852

53+
if (this.buildProd) {
54+
compiler.options.externals = [
55+
// eslint-disable-next-line
56+
function ({ _, request }, callback) {
57+
[...polyfillsManager.external].map(([key]) => {
58+
const pattern = new RegExp(`${key}$`);
59+
if (pattern.test(request)) {
60+
return callback(null, `module ${request}`);
61+
}
62+
return callback();
63+
});
64+
},
65+
];
66+
} else {
67+
compiler.options.resolve.fallback = {
68+
...Object.fromEntries(
69+
[...polyfillsManager.external].map(([key, value]) => [key, value]),
70+
),
71+
...compiler.options.resolve.fallback,
72+
};
73+
}
74+
4975
compiler.options.resolve.alias = {
5076
...Object.fromEntries(
5177
[...polyfillsManager.alias].map(([key, value]) => [key, value]),

lib/build/dispatcher/dispatcher.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
injectFilesInMem,
1515
} from '#utils';
1616
import { Messages } from '#constants';
17-
import { vulcan } from '#env';
17+
import vulcan from '../../env/vulcan.env.js';
1818
import {
1919
getAliasPath,
2020
createDotEnvFile,
@@ -378,6 +378,7 @@ class Dispatcher {
378378

379379
await vulcan.createVulcanEnv(
380380
{
381+
builder: builderSelected,
381382
entry: originalEntry, // original entry
382383
preset: buildConfig.preset.name,
383384
mode: buildConfig.preset.mode,

lib/commands/build.commands.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Commands } from '#namespaces';
22
import { feedback } from '#utils';
3-
import { vulcan } from '#env';
3+
import vulcan from '../env/vulcan.env.js';
44

55
/**
66
* Retrieves a configuration value based on priority.

lib/env/server.env.js

+17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { runServer, EdgeRuntime } from 'edge-runtime';
44
import chokidar from 'chokidar';
55
import runtime from './runtime.env.js';
66
import vulcan from './vulcan.env.js';
7+
import buildCommand from '../commands/build.commands.js';
78

89
let currentServer;
910
let isChangeHandlerRunning = false;
@@ -37,13 +38,28 @@ async function initializeServer(port, workerCode) {
3738
return runServer({ port, host: '0.0.0.0', runtime: execution });
3839
}
3940

41+
/**
42+
* Build to Local Server with polyfill external
43+
*/
44+
async function buildToLocalServer() {
45+
const { entry } = (await vulcan.readVulcanEnv('local')) || {};
46+
47+
if (!entry) {
48+
throw new Error('fail load build file');
49+
}
50+
globalThis.buildProd = false;
51+
await buildCommand({});
52+
}
53+
4054
/**
4155
* Handle server operations: start, restart.
4256
* @param {string} workerPath - Path to the worker file.
4357
* @param {number} port - The port number.
4458
*/
4559
async function manageServer(workerPath, port) {
4660
try {
61+
await buildToLocalServer();
62+
4763
const workerCode = await readWorkerCode(workerPath);
4864

4965
if (currentServer) {
@@ -66,6 +82,7 @@ async function manageServer(workerPath, port) {
6682
}
6783
} catch (error) {
6884
debug.error(error);
85+
feedback.server.error('Please before run command build');
6986
process.exit(1);
7087
}
7188
}

lib/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ function startVulcanProgram() {
8888
)
8989
.action(async (options) => {
9090
const { buildCommand } = await import('#commands');
91+
globalThis.buildProd = true;
9192
await buildCommand(options);
9293
});
9394

0 commit comments

Comments
 (0)