Skip to content

Commit d793c90

Browse files
authored
feat: storage api local server (#214)
2 parents 89923a2 + 4c456b2 commit d793c90

40 files changed

+1476
-415
lines changed

lib/build/bundlers/bundler-base.js lib/build/bundlers/base.bunlders.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import merge from 'lodash.merge';
66
* Base class for a bundler.
77
* @class
88
*/
9-
class BundlerBase {
9+
class BaseBundlers {
1010
/**
1111
* Represents a configuration object.
1212
* @typedef {object} BuilderConfig
@@ -60,7 +60,7 @@ class BundlerBase {
6060
// This method can be overridden by subclasses
6161
// as it does not require the use of `this`
6262
// eslint-disable-next-line class-methods-use-this
63-
throw new Error('Running BundlerBase run method');
63+
throw new Error('Running BaseBundlers run method');
6464
}
6565

6666
/**
@@ -98,4 +98,4 @@ class BundlerBase {
9898
}
9999
}
100100

101-
export default BundlerBase;
101+
export default BaseBundlers;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as esbuild from 'esbuild';
2+
import lodash from 'lodash';
3+
4+
import { Messages } from '#constants';
5+
import { debug } from '#utils';
6+
7+
import BaseBundlers from '../base.bunlders.js';
8+
import AzionEsbuildConfig from './esbuild.config.js';
9+
import ESBuildNodeModulePlugin from './plugins/node-polyfills/index.js';
10+
import ESBuildAzionModulePlugin from './plugins/azion-polyfills/index.js';
11+
12+
/**
13+
* Class representing an ESBuild bundler, extending BaseBundlers.
14+
*/
15+
class Esbuild extends BaseBundlers {
16+
/**
17+
* Asynchronous method to run the ESBuild bundler.
18+
*/
19+
async run() {
20+
let config = lodash.cloneDeep(AzionEsbuildConfig);
21+
config.entryPoints = [this.builderConfig.entry];
22+
23+
if (!config.plugins) config.plugins = [];
24+
25+
// merge config common
26+
config = super.mergeConfig(config);
27+
config = this.applyConfig(config);
28+
29+
try {
30+
await esbuild.build(config);
31+
} catch (error) {
32+
debug.error(error);
33+
throw Error(Messages.build.error.vulcan_build_failed);
34+
}
35+
}
36+
37+
/**
38+
* Applies specific configurations to the ESBuild config.
39+
* @param {object} config - ESBuild configuration object.
40+
* @returns {object} - Updated ESBuild configuration object.
41+
*/
42+
applyConfig(config) {
43+
const updatedConfig = { ...config };
44+
// use polyfill with useNodePolyfills and preset mode compute
45+
const useNodePolyfills =
46+
(this.builderConfig?.useNodePolyfills ||
47+
this.customConfigPreset?.useNodePolyfills ||
48+
this.customConfigLocal?.useNodePolyfills) &&
49+
this.presetMode === 'compute';
50+
51+
if (!updatedConfig.plugins) updatedConfig.plugins = [];
52+
if (useNodePolyfills) {
53+
updatedConfig.plugins.push(ESBuildNodeModulePlugin(globalThis.buildProd));
54+
}
55+
56+
// plugin resolve azion:
57+
updatedConfig.plugins.push(ESBuildAzionModulePlugin(globalThis.buildProd));
58+
59+
// inject content in worker initial code.
60+
if (this.builderConfig.contentToInject) {
61+
const workerInitContent = this.builderConfig.contentToInject;
62+
63+
if (updatedConfig.banner?.js) {
64+
updatedConfig.banner.js = `${updatedConfig.banner.js} ${workerInitContent}`;
65+
} else {
66+
updatedConfig.banner = { js: workerInitContent };
67+
}
68+
}
69+
return updatedConfig;
70+
}
71+
}
72+
73+
export default Esbuild;

lib/build/bundlers/esbuild/index.test.js lib/build/bundlers/esbuild/esbuild.bundlers.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fs from 'fs';
22
import tmp from 'tmp';
3-
import Esbuild from './index.js';
3+
import Esbuild from './esbuild.bundlers.js';
44
import AzionEsbuildConfig from './esbuild.config.js';
55

66
// IN MILESECONDS

lib/build/bundlers/esbuild/index.js

+1-67
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,3 @@
1-
import * as esbuild from 'esbuild';
2-
import lodash from 'lodash';
3-
4-
import { Messages } from '#constants';
5-
import { debug } from '#utils';
6-
7-
import BundlerBase from '../bundler-base.js';
8-
import AzionEsbuildConfig from './esbuild.config.js';
9-
import ESBuildNodeModulePlugin from './plugins/node-polyfills/index.js';
10-
11-
/**
12-
* Class representing an ESBuild bundler, extending BundlerBase.
13-
*/
14-
class Esbuild extends BundlerBase {
15-
/**
16-
* Asynchronous method to run the ESBuild bundler.
17-
*/
18-
async run() {
19-
let config = lodash.cloneDeep(AzionEsbuildConfig);
20-
config.entryPoints = [this.builderConfig.entry];
21-
22-
if (!config.plugins) config.plugins = [];
23-
24-
// merge config common
25-
config = super.mergeConfig(config);
26-
config = this.applyConfig(config);
27-
28-
try {
29-
await esbuild.build(config);
30-
} catch (error) {
31-
debug.error(error);
32-
throw Error(Messages.build.error.vulcan_build_failed);
33-
}
34-
}
35-
36-
/**
37-
* Applies specific configurations to the ESBuild config.
38-
* @param {object} config - ESBuild configuration object.
39-
* @returns {object} - Updated ESBuild configuration object.
40-
*/
41-
applyConfig(config) {
42-
const updatedConfig = { ...config };
43-
// use polyfill with useNodePolyfills and preset mode compute
44-
const useNodePolyfills =
45-
(this.builderConfig?.useNodePolyfills ||
46-
this.customConfigPreset?.useNodePolyfills ||
47-
this.customConfigLocal?.useNodePolyfills) &&
48-
this.presetMode === 'compute';
49-
50-
if (useNodePolyfills) {
51-
if (!updatedConfig.plugins) updatedConfig.plugins = [];
52-
updatedConfig.plugins.push(ESBuildNodeModulePlugin(globalThis.buildProd));
53-
}
54-
55-
// inject content in worker initial code.
56-
if (this.builderConfig.contentToInject) {
57-
const workerInitContent = this.builderConfig.contentToInject;
58-
59-
if (updatedConfig.banner?.js) {
60-
updatedConfig.banner.js = `${updatedConfig.banner.js} ${workerInitContent}`;
61-
} else {
62-
updatedConfig.banner = { js: workerInitContent };
63-
}
64-
}
65-
return updatedConfig;
66-
}
67-
}
1+
import Esbuild from './esbuild.bundlers.js';
682

693
export default Esbuild;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/* eslint-disable consistent-return */
2+
import fs from 'fs';
3+
import path from 'path';
4+
import PolyfillsManager from '../../../polyfills/index.js';
5+
6+
/**
7+
* ESBuild Azion Module Plugin for polyfilling node modules.
8+
* @param {boolean} buildProd Parameter to identify whether the build is dev or prod
9+
* @returns {object} - ESBuild plugin object.
10+
*/
11+
const ESBuildAzionModulePlugin = (buildProd) => {
12+
const NAME = 'vulcan-azion-modules-polyfills';
13+
const NAMESPACE = NAME;
14+
const filter = /^azion:/;
15+
16+
return {
17+
/**
18+
* Name and setup of the ESBuild plugin.
19+
* @param {object} build - ESBuild build object.
20+
*/
21+
name: NAME,
22+
setup: (build) => {
23+
const polyfillManager = PolyfillsManager.buildPolyfills();
24+
25+
const options = build.initialOptions;
26+
27+
// external
28+
if (buildProd) {
29+
options.external = options.external || [];
30+
[...polyfillManager.external].forEach(([key]) => {
31+
if (/^[^:]+:/.test(key) && !options.external.includes(key)) {
32+
options.external.push(key);
33+
}
34+
});
35+
}
36+
37+
/**
38+
* Resolve callback for ESBuild.
39+
* @param {object} args - Arguments object.
40+
* @returns {object|undefined} - Object with path and namespace or undefined.
41+
*/
42+
build.onResolve({ filter }, async (args) => {
43+
if (!buildProd && polyfillManager.external.has(args.path)) {
44+
return {
45+
path: args.path,
46+
namespace: NAMESPACE,
47+
};
48+
}
49+
if (!polyfillManager.external.has(args.path)) {
50+
return;
51+
}
52+
53+
// external bypass
54+
if (
55+
options?.external?.length > 0 &&
56+
options?.external?.includes(args.path)
57+
) {
58+
return;
59+
}
60+
61+
return {
62+
path: args.path,
63+
namespace: NAMESPACE,
64+
};
65+
});
66+
67+
/**
68+
* Load callback for node module files.
69+
* @param {object} args - Arguments object.
70+
* @returns {object} - Object with loader, contents, and resolve directory.
71+
*/
72+
build.onLoad({ filter, namespace: NAMESPACE }, async (args) => {
73+
if (!polyfillManager.external.has(args.path)) {
74+
return;
75+
}
76+
const resolved = polyfillManager.external.get(args.path);
77+
const contents = await fs.promises.readFile(resolved, 'utf8');
78+
const resolveDir = path.dirname(resolved);
79+
80+
return {
81+
loader: 'js',
82+
contents,
83+
resolveDir,
84+
};
85+
});
86+
},
87+
};
88+
};
89+
90+
export default ESBuildAzionModulePlugin;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import * as esbuild from 'esbuild';
2+
import ESBuildAzionModulePlugin from './azion-polyfills.plugins.js';
3+
4+
describe('Esbuild Azion Plugin', () => {
5+
it('should resolve the azion module: as external', async () => {
6+
const results = await esbuild.build({
7+
write: false,
8+
target: 'es2022',
9+
format: 'esm',
10+
platform: 'browser',
11+
mainFields: ['browser', 'main', 'module'],
12+
bundle: true,
13+
minify: false,
14+
stdin: {
15+
contents: 'import storage from "azion:storage";',
16+
},
17+
plugins: [ESBuildAzionModulePlugin(true)],
18+
});
19+
20+
expect(results.outputFiles.at(0)?.text.trim()).toContain(
21+
'import storage from "azion:storage";',
22+
);
23+
});
24+
25+
it('should resolve the azion module: for local execution', async () => {
26+
const results = await esbuild.build({
27+
write: false,
28+
target: 'es2022',
29+
format: 'esm',
30+
platform: 'browser',
31+
mainFields: ['browser', 'main', 'module'],
32+
bundle: true,
33+
minify: false,
34+
stdin: {
35+
contents: 'import storage from "azion:storage";',
36+
},
37+
plugins: [ESBuildAzionModulePlugin(false)],
38+
});
39+
40+
expect(results.outputFiles.at(0)?.text.trim()).toContain(
41+
'vulcan-azion-modules-polyfills',
42+
);
43+
});
44+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import AzionPolyfillPlugin from './azion-polyfills.plugins.js';
2+
3+
export default AzionPolyfillPlugin;

0 commit comments

Comments
 (0)