edge-functions 1.0.0 → 1.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.
Files changed (111) hide show
  1. package/.eslintrc.json +60 -15
  2. package/.github/workflows/major.yml +1 -1
  3. package/.github/workflows/minor.yml +1 -2
  4. package/README.md +36 -0
  5. package/aliases.js +1 -1
  6. package/docs/overview.md +4 -3
  7. package/docs/presets.md +18 -6
  8. package/examples/angular-static/package.json +0 -1
  9. package/examples/simple-js-esm/main.js +13 -8
  10. package/examples/simple-js-esm-node/index.js +45 -0
  11. package/examples/simple-ts-esm/main.ts +24 -0
  12. package/examples/simple-ts-esm/messages.ts +11 -0
  13. package/examples/simple-ts-esm/package.json +9 -0
  14. package/examples/simple-ts-esm/tsconfig.json +109 -0
  15. package/examples/simple-ts-esm/yarn.lock +8 -0
  16. package/examples/vue-vite-static/README.md +29 -0
  17. package/examples/vue-vite-static/index.html +13 -0
  18. package/examples/vue-vite-static/package.json +18 -0
  19. package/examples/vue-vite-static/public/favicon.ico +0 -0
  20. package/examples/vue-vite-static/src/App.vue +85 -0
  21. package/examples/vue-vite-static/src/assets/base.css +73 -0
  22. package/examples/vue-vite-static/src/assets/logo.svg +1 -0
  23. package/examples/vue-vite-static/src/assets/main.css +35 -0
  24. package/examples/vue-vite-static/src/components/HelloWorld.vue +44 -0
  25. package/examples/vue-vite-static/src/components/TheWelcome.vue +86 -0
  26. package/examples/vue-vite-static/src/components/WelcomeItem.vue +86 -0
  27. package/examples/vue-vite-static/src/components/icons/IconCommunity.vue +7 -0
  28. package/examples/vue-vite-static/src/components/icons/IconDocumentation.vue +7 -0
  29. package/examples/vue-vite-static/src/components/icons/IconEcosystem.vue +7 -0
  30. package/examples/vue-vite-static/src/components/icons/IconSupport.vue +7 -0
  31. package/examples/vue-vite-static/src/components/icons/IconTooling.vue +19 -0
  32. package/examples/vue-vite-static/src/main.js +11 -0
  33. package/examples/vue-vite-static/src/router/index.js +23 -0
  34. package/examples/vue-vite-static/src/views/AboutView.vue +15 -0
  35. package/examples/vue-vite-static/src/views/HomeView.vue +9 -0
  36. package/examples/vue-vite-static/vite.config.js +16 -0
  37. package/jsconfig.json +1 -1
  38. package/lib/build/bundlers/esbuild/esbuild.config.js +12 -0
  39. package/lib/build/bundlers/esbuild/index.js +46 -0
  40. package/lib/build/bundlers/esbuild/plugins/node-polyfills/index.js +147 -0
  41. package/lib/build/bundlers/esbuild/plugins/node-polyfills/node-polyfills-paths.js +124 -0
  42. package/lib/build/bundlers/index.js +2 -2
  43. package/lib/build/bundlers/webpack/index.js +16 -7
  44. package/lib/build/bundlers/webpack/webpack.config.js +5 -25
  45. package/lib/build/dispatcher/dispatcher.js +116 -66
  46. package/lib/constants/framework-initializer.constants.js +51 -0
  47. package/lib/constants/index.js +4 -1
  48. package/lib/constants/messages/build.messages.js +2 -0
  49. package/lib/constants/messages/env.messages.js +5 -3
  50. package/lib/constants/messages/global.messages.js +4 -1
  51. package/lib/env/polyfills/FetchEvent.polyfills.js +13 -0
  52. package/lib/env/polyfills/fetch.polyfills.js +39 -0
  53. package/lib/env/polyfills/index.js +4 -0
  54. package/lib/env/runtime.env.js +57 -63
  55. package/lib/env/server.env.js +32 -76
  56. package/lib/main.js +234 -90
  57. package/lib/notations/namespaces.js +5 -0
  58. package/lib/platform/actions/core/auth.actions.js +1 -1
  59. package/lib/platform/actions/core/propagation.actions.js +8 -5
  60. package/lib/platform/actions/core/storage.actions.js +1 -1
  61. package/lib/platform/actions/function/showFunctionLogs.actions.js +71 -92
  62. package/lib/platform/edgehooks/debugRequest/debugRequest.hooks.js +28 -0
  63. package/lib/platform/edgehooks/debugRequest/index.js +3 -0
  64. package/lib/platform/edgehooks/index.js +4 -1
  65. package/lib/polyfills/FetchEvent.polyfills.js +13 -0
  66. package/lib/polyfills/fetch.polyfills.js +39 -0
  67. package/lib/polyfills/index.js +4 -0
  68. package/lib/presets/custom/angular/deliver/config.js +2 -4
  69. package/lib/presets/custom/angular/deliver/handler.js +12 -5
  70. package/lib/presets/custom/angular/deliver/prebuild.js +8 -11
  71. package/lib/presets/custom/astro/deliver/config.js +2 -4
  72. package/lib/presets/custom/astro/deliver/handler.js +14 -7
  73. package/lib/presets/custom/astro/deliver/prebuild.js +18 -21
  74. package/lib/presets/custom/hexo/deliver/config.js +2 -4
  75. package/lib/presets/custom/hexo/deliver/handler.js +13 -6
  76. package/lib/presets/custom/hexo/deliver/prebuild.js +18 -21
  77. package/lib/presets/custom/next/deliver/config.js +2 -6
  78. package/lib/presets/custom/next/deliver/handler.js +14 -7
  79. package/lib/presets/custom/next/deliver/prebuild.js +37 -40
  80. package/lib/presets/custom/react/deliver/config.js +2 -4
  81. package/lib/presets/custom/react/deliver/handler.js +10 -3
  82. package/lib/presets/custom/react/deliver/prebuild.js +4 -7
  83. package/lib/presets/custom/vue/deliver/config.js +2 -4
  84. package/lib/presets/custom/vue/deliver/handler.js +10 -3
  85. package/lib/presets/custom/vue/deliver/prebuild.js +66 -10
  86. package/lib/presets/default/html/deliver/config.js +1 -4
  87. package/lib/presets/default/html/deliver/handler.js +14 -7
  88. package/lib/presets/default/html/deliver/prebuild.js +3 -2
  89. package/lib/presets/default/javascript/compute/config.js +2 -5
  90. package/lib/presets/default/javascript/compute/handler.js +15 -4
  91. package/lib/presets/default/javascript/compute/prebuild.js +2 -1
  92. package/lib/presets/default/typescript/compute/config.js +10 -0
  93. package/lib/presets/default/typescript/compute/handler.js +16 -0
  94. package/lib/presets/default/typescript/compute/prebuild.js +7 -0
  95. package/lib/providers/azion/worker.js +6 -2
  96. package/lib/utils/exec/exec.utils.js +34 -23
  97. package/lib/utils/feedback/feedback.utils.js +6 -2
  98. package/lib/utils/getAbsoluteLibDirPath/getAbsoluteLibDirPath.utils.js +11 -2
  99. package/lib/utils/getVulcanBuildId/getVulcanBuildId.utils.js +1 -1
  100. package/lib/utils/index.js +4 -2
  101. package/lib/utils/overrideStaticOutputPath/overrideStaticOutputPath.utils.js +2 -2
  102. package/lib/utils/presets/index.js +3 -0
  103. package/lib/utils/presets/presets.utils.js +169 -0
  104. package/lib/utils/spinner/index.js +3 -0
  105. package/lib/utils/spinner/spinner.utils.js +32 -0
  106. package/package.json +17 -4
  107. package/examples/hexo-static/yarn.lock +0 -1625
  108. package/lib/build/polyfills/index.js +0 -0
  109. package/lib/utils/getPresetsList/getPresetsList.utils.js +0 -50
  110. package/lib/utils/getPresetsList/index.js +0 -3
  111. /package/lib/utils/{getPresetsList/getPresetsList.utils.test.js → presets/presets.utils.test.js} +0 -0
@@ -0,0 +1,147 @@
1
+ // Based on https://github.com/remorses/esbuild-plugins/blob/master/node-modules-polyfill/src/index.ts
2
+
3
+ import escapeStringRegexp from 'escape-string-regexp';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+
7
+ import builtinsPolyfills from './node-polyfills-paths.js';
8
+
9
+ const NAME = 'node-modules-polyfills';
10
+ const NAMESPACE = NAME;
11
+
12
+ /**
13
+ * Remove ending slash
14
+ * @param {string} importee - the imported path
15
+ * @returns {string} the new path without ending slash
16
+ */
17
+ function removeEndingSlash(importee) {
18
+ if (importee && importee.slice(-1) === '/') {
19
+ return importee.slice(0, -1);
20
+ }
21
+
22
+ return importee;
23
+ }
24
+
25
+ /**
26
+ * Generates a template for commonjs with module require
27
+ * @param {string} importPath - the import path
28
+ * @returns {string} the template
29
+ */
30
+ function commonJsTemplate({ importPath }) {
31
+ return `
32
+ const polyfill = require('${importPath}')
33
+
34
+ if (polyfill && polyfill.default) {
35
+ module.exports = polyfill.default
36
+ for (let k in polyfill) {
37
+ module.exports[k] = polyfill[k]
38
+ }
39
+ } else if (polyfill) {
40
+ module.exports = polyfill
41
+ }
42
+
43
+
44
+ `;
45
+ }
46
+
47
+ /**
48
+ * Plugin to use nodejs polyfills
49
+ * @param {object} options - Options to use with the plugin
50
+ * @returns {object} - the plugin
51
+ */
52
+ export function NodeModulesPolyfillPlugin(
53
+ options = {},
54
+ ) {
55
+ const { namespace = NAMESPACE, name = NAME } = options;
56
+ if (namespace.endsWith('commonjs')) {
57
+ throw new Error(`namespace ${namespace} must not end with commonjs`);
58
+ }
59
+ // this namespace is needed to make ES modules expose their default export to require:
60
+ // require('assert') will give you import('assert').default
61
+ const commonjsNamespace = `${namespace}-commonjs`;
62
+ const polyfilledBuiltins = builtinsPolyfills();
63
+ const polyfilledBuiltinsNames = [...polyfilledBuiltins.keys()];
64
+
65
+ return {
66
+ name,
67
+ setup: function setup({ onLoad, onResolve, initialOptions }) {
68
+ // polyfills contain global keyword, it must be defined
69
+ if (initialOptions?.define && !initialOptions.define?.global) {
70
+ // eslint-disable-next-line
71
+ initialOptions.define.global = 'globalThis';
72
+ } else if (!initialOptions?.define) {
73
+ // eslint-disable-next-line
74
+ initialOptions.define = { global: 'globalThis' };
75
+ }
76
+
77
+ // TODO these polyfill module cannot import anything, is that ok?
78
+ async function loader(
79
+ args,
80
+ ) {
81
+ try {
82
+ const argsPath = args.path.replace(/^node:/, '');
83
+ const isCommonjs = args.namespace.endsWith('commonjs');
84
+
85
+ const resolved = polyfilledBuiltins.get(
86
+ removeEndingSlash(argsPath),
87
+ );
88
+ const contents = await (
89
+ await fs.promises.readFile(resolved)
90
+ ).toString();
91
+ const resolveDir = path.dirname(resolved);
92
+
93
+ if (isCommonjs) {
94
+ return {
95
+ loader: 'js',
96
+ contents: commonJsTemplate({
97
+ importPath: argsPath,
98
+ }),
99
+ resolveDir,
100
+ };
101
+ }
102
+ return {
103
+ loader: 'js',
104
+ contents,
105
+ resolveDir,
106
+ };
107
+ } catch (e) {
108
+ console.error('node-modules-polyfill', e);
109
+ return {
110
+ contents: 'export {}',
111
+ loader: 'js',
112
+ };
113
+ }
114
+ }
115
+ onLoad({ filter: /.*/, namespace }, loader);
116
+ onLoad({ filter: /.*/, namespace: commonjsNamespace }, loader);
117
+ const filter = new RegExp(
118
+ [
119
+ ...polyfilledBuiltinsNames,
120
+ ...polyfilledBuiltinsNames.map((n) => `node:${n}`),
121
+ ]
122
+ .map(escapeStringRegexp)
123
+ .join('|'), // TODO builtins could end with slash, keep in mind in regex
124
+ );
125
+ async function resolver(args) {
126
+ const argsPath = args.path.replace(/^node:/, '');
127
+ const ignoreRequire = args.namespace === commonjsNamespace;
128
+
129
+ if (!polyfilledBuiltins.has(argsPath)) {
130
+ return;
131
+ }
132
+
133
+ const isCommonjs = !ignoreRequire && args.kind === 'require-call';
134
+
135
+ // eslint-disable-next-line
136
+ return {
137
+ namespace: isCommonjs ? commonjsNamespace : namespace,
138
+ path: argsPath,
139
+ };
140
+ }
141
+ onResolve({ filter }, resolver);
142
+ // onResolve({ filter: /.*/, namespace }, resolver)
143
+ },
144
+ };
145
+ }
146
+
147
+ export default NodeModulesPolyfillPlugin;
@@ -0,0 +1,124 @@
1
+ // Taken from https://github.com/ionic-team/rollup-plugin-node-polyfills/blob/master/src/modules.ts
2
+
3
+ import { createRequire } from 'module';
4
+
5
+ const require = createRequire(import.meta.url);
6
+
7
+ /**
8
+ * Generates a Map composed by the module name and location
9
+ * @returns {Map} - the map with module locations
10
+ */
11
+ function builtinsPolyfills() {
12
+ const libs = new Map();
13
+
14
+ libs.set(
15
+ 'process',
16
+ require.resolve('rollup-plugin-node-polyfills/polyfills/process-es6'),
17
+ );
18
+ libs.set(
19
+ 'buffer',
20
+ require.resolve('rollup-plugin-node-polyfills/polyfills/buffer-es6'),
21
+ );
22
+ libs.set(
23
+ 'util',
24
+ require.resolve('rollup-plugin-node-polyfills/polyfills/util'),
25
+ );
26
+ libs.set('sys', libs.get('util'));
27
+ libs.set(
28
+ 'events',
29
+ require.resolve('rollup-plugin-node-polyfills/polyfills/events'),
30
+ );
31
+ libs.set(
32
+ 'stream',
33
+ require.resolve('rollup-plugin-node-polyfills/polyfills/stream'),
34
+ );
35
+ libs.set(
36
+ 'path',
37
+ require.resolve('rollup-plugin-node-polyfills/polyfills/path'),
38
+ );
39
+ libs.set(
40
+ 'querystring',
41
+ require.resolve('rollup-plugin-node-polyfills/polyfills/qs'),
42
+ );
43
+ libs.set(
44
+ 'punycode',
45
+ require.resolve('rollup-plugin-node-polyfills/polyfills/punycode'),
46
+ );
47
+ libs.set(
48
+ 'url',
49
+ require.resolve('rollup-plugin-node-polyfills/polyfills/url'),
50
+ );
51
+ libs.set(
52
+ 'string_decoder',
53
+ require.resolve(
54
+ 'rollup-plugin-node-polyfills/polyfills/string-decoder',
55
+ ),
56
+ );
57
+ libs.set(
58
+ 'http',
59
+ require.resolve('rollup-plugin-node-polyfills/polyfills/http'),
60
+ );
61
+ libs.set(
62
+ 'https',
63
+ require.resolve('rollup-plugin-node-polyfills/polyfills/http'),
64
+ );
65
+ libs.set('os', require.resolve('rollup-plugin-node-polyfills/polyfills/os'));
66
+ libs.set(
67
+ 'assert',
68
+ require.resolve('rollup-plugin-node-polyfills/polyfills/assert'),
69
+ );
70
+ libs.set(
71
+ 'constants',
72
+ require.resolve('rollup-plugin-node-polyfills/polyfills/constants'),
73
+ );
74
+ libs.set(
75
+ '_stream_duplex',
76
+ require.resolve(
77
+ 'rollup-plugin-node-polyfills/polyfills/readable-stream/duplex',
78
+ ),
79
+ );
80
+ libs.set(
81
+ '_stream_passthrough',
82
+ require.resolve(
83
+ 'rollup-plugin-node-polyfills/polyfills/readable-stream/passthrough',
84
+ ),
85
+ );
86
+ libs.set(
87
+ '_stream_readable',
88
+ require.resolve(
89
+ 'rollup-plugin-node-polyfills/polyfills/readable-stream/readable',
90
+ ),
91
+ );
92
+ libs.set(
93
+ '_stream_writable',
94
+ require.resolve(
95
+ 'rollup-plugin-node-polyfills/polyfills/readable-stream/writable',
96
+ ),
97
+ );
98
+ libs.set(
99
+ '_stream_transform',
100
+ require.resolve(
101
+ 'rollup-plugin-node-polyfills/polyfills/readable-stream/transform',
102
+ ),
103
+ );
104
+ libs.set(
105
+ 'console',
106
+ require.resolve('rollup-plugin-node-polyfills/polyfills/console'),
107
+ );
108
+ libs.set(
109
+ 'zlib',
110
+ require.resolve('rollup-plugin-node-polyfills/polyfills/zlib'),
111
+ );
112
+ libs.set(
113
+ 'tty',
114
+ require.resolve('rollup-plugin-node-polyfills/polyfills/tty'),
115
+ );
116
+ libs.set(
117
+ 'domain',
118
+ require.resolve('rollup-plugin-node-polyfills/polyfills/domain'),
119
+ );
120
+
121
+ return libs;
122
+ }
123
+
124
+ export default builtinsPolyfills;
@@ -1,4 +1,4 @@
1
1
  import Webpack from './webpack/index.js';
2
+ import Esbuild from './esbuild/index.js';
2
3
 
3
- // eslint-disable-next-line import/prefer-default-export
4
- export { Webpack };
4
+ export { Esbuild, Webpack };
@@ -1,26 +1,35 @@
1
- import webpack from 'webpack';
2
1
  import { promisify } from 'util';
2
+ import webpack from 'webpack';
3
+ import { merge } from 'webpack-merge';
4
+
3
5
  import { feedback, debug } from '#utils';
4
6
  import { Messages } from '#constants';
5
7
 
6
8
  import AzionWebpackConfig from './webpack.config.js';
7
9
 
8
10
  class Webpack {
9
- constructor(customConfig, useNodePolyfills) {
10
- this.customConfig = customConfig;
11
- this.useNodePolyfills = useNodePolyfills;
11
+ constructor(builderConfig) {
12
+ this.builderConfig = builderConfig;
13
+ this.customConfig = builderConfig.custom;
12
14
  }
13
15
 
14
16
  run = async () => {
15
17
  const runWebpack = promisify(webpack);
16
18
 
17
- const config = AzionWebpackConfig;
18
- config.entry = this.customConfig.entry;
19
+ let config = AzionWebpackConfig;
20
+ config.entry = this.builderConfig.entry;
19
21
  config.plugins = [
20
- new webpack.ProgressPlugin(),
22
+ new webpack.DefinePlugin({
23
+ AZION_VERSION_ID: JSON.stringify(this.builderConfig.buildId),
24
+ }),
21
25
  ...config.plugins,
22
26
  ];
23
27
 
28
+ const hasCustomConfig = Object.keys(this.customConfig).length > 0;
29
+ if (hasCustomConfig) {
30
+ config = merge(this.customConfig, config);
31
+ }
32
+
24
33
  try {
25
34
  const stats = await runWebpack(config);
26
35
 
@@ -1,24 +1,10 @@
1
1
  import webpack from 'webpack';
2
2
  import { join } from 'path';
3
- import { writeFile, mkdir } from 'fs/promises';
4
- import { generateTimestamp } from '#utils';
3
+ import { fileURLToPath } from 'url';
5
4
 
6
5
  const projectRoot = process.cwd();
7
- const outputPath = join(projectRoot, '.edge');
8
-
9
- /**
10
- * Generates a build ID and saves it in the .env file (for deploy).
11
- * @returns {Promise<string>} The generated build ID.
12
- */
13
- async function generateBuildId() {
14
- const envFilePath = join(outputPath, '.env');
15
- const BUILD_VERSION___AKA__VERSION_ID = generateTimestamp();
16
- const envContent = `VERSION_ID=${BUILD_VERSION___AKA__VERSION_ID}`;
17
-
18
- await mkdir(outputPath, { recursive: true });
19
- await writeFile(envFilePath, envContent);
20
- return BUILD_VERSION___AKA__VERSION_ID;
21
- }
6
+ const isWindows = process.platform === 'win32';
7
+ const outputPath = isWindows ? fileURLToPath(new URL(`file:///${join(projectRoot, '.edge')}`)) : join(projectRoot, '.edge');
22
8
 
23
9
  export default {
24
10
  output: {
@@ -27,12 +13,6 @@ export default {
27
13
  globalObject: 'this',
28
14
  },
29
15
  mode: 'production',
30
- target: 'webworker',
31
- plugins: [
32
- new webpack.DefinePlugin({
33
- AZION: {
34
- VERSION_ID: JSON.stringify(await generateBuildId()),
35
- },
36
- }),
37
- ],
16
+ target: ['webworker', 'es2022'],
17
+ plugins: [new webpack.ProgressPlugin()],
38
18
  };
@@ -1,34 +1,28 @@
1
1
  import { join, resolve } from 'path';
2
- import { readFileSync, readdirSync, existsSync } from 'fs';
3
- import { writeFile, rm } from 'fs/promises';
4
- import { Webpack } from '#bundlers';
5
- import { feedback, generateTimestamp, getAbsoluteLibDirPath } from '#utils';
2
+ import {
3
+ readFileSync, existsSync, mkdirSync, writeFileSync, rmSync,
4
+ } from 'fs';
5
+ import { fileURLToPath } from 'url';
6
+ import { Esbuild, Webpack } from '#bundlers';
7
+ import {
8
+ feedback, debug, generateTimestamp, getAbsoluteLibDirPath, presets,
9
+ } from '#utils';
6
10
  import { Messages } from '#constants';
7
11
 
8
12
  const vulcanLibPath = getAbsoluteLibDirPath();
9
13
  const vulcanRootPath = resolve(vulcanLibPath, '..');
14
+ const isWindows = process.platform === 'win32';
10
15
 
11
16
  /**
12
- * Get the valid build presets based on the folders inside the presets/default
13
- * and presets/custom directories.
14
- * @returns {string[]} An array of valid build presets.
17
+ * Get the path corresponding to a specific alias defined in the package.json.
18
+ * @param {string} alias - The desired alias.
19
+ * @returns {string} The path corresponding to the alias.
20
+ */
21
+ /**
22
+ * Get the path corresponding to a specific alias defined in the package.json.
23
+ * @param {string} alias - The desired alias.
24
+ * @returns {string} The path corresponding to the alias.
15
25
  */
16
- function getValidPresets() {
17
- const types = ['default', 'custom'];
18
- const validPresets = [];
19
-
20
- types.forEach((type) => {
21
- const presetsPath = join(vulcanLibPath, 'presets', type);
22
- const directories = readdirSync(presetsPath, { withFileTypes: true })
23
- .filter((dirent) => dirent.isDirectory())
24
- .map((dirent) => dirent.name);
25
-
26
- validPresets.push(...directories);
27
- });
28
-
29
- return validPresets;
30
- }
31
-
32
26
  /**
33
27
  * Get the path corresponding to a specific alias defined in the package.json.
34
28
  * @param {string} alias - The desired alias.
@@ -40,9 +34,12 @@ async function getAliasPath(alias) {
40
34
  const packageJson = JSON.parse(packageJsonContent);
41
35
  let aliasPath = packageJson.imports[`#${alias}`];
42
36
  aliasPath = aliasPath.replace('./', `${vulcanRootPath}/`);
37
+ if (isWindows) {
38
+ aliasPath = aliasPath.replace(/[\\/]/g, '\\\\');
39
+ }
40
+
43
41
  return aliasPath;
44
42
  }
45
-
46
43
  /**
47
44
  * Move requires and imports to file init
48
45
  * @param {string} entryContent - The file content to be fixed.
@@ -64,7 +61,6 @@ function fixImportsAndRequestsPlace(entryContent) {
64
61
 
65
62
  return newCode;
66
63
  }
67
-
68
64
  /**
69
65
  * Get a build context based on arguments
70
66
  * @param {string} preset - The build preset.
@@ -73,14 +69,13 @@ function fixImportsAndRequestsPlace(entryContent) {
73
69
  * @returns {any} The context that will be used in build.
74
70
  */
75
71
  async function loadBuildContext(preset, entry, mode) {
76
- const VALID_BUILD_PRESETS = getValidPresets();
72
+ const VALID_BUILD_PRESETS = presets.getKeys();
73
+
77
74
  const validPreset = VALID_BUILD_PRESETS.includes(preset);
78
75
 
79
76
  if (!validPreset) {
80
- throw Error(
81
- 'Invalid build preset. Available presets: ',
82
- VALID_BUILD_PRESETS.concat(','),
83
- );
77
+ feedback.build.error(Messages.build.error.invalid_preset);
78
+ process.exit(1);
84
79
  }
85
80
 
86
81
  let configFilePath;
@@ -102,8 +97,14 @@ async function loadBuildContext(preset, entry, mode) {
102
97
  configFilePath = join(modePath, 'config.js');
103
98
  prebuildFilePath = join(modePath, 'prebuild.js');
104
99
  handlerFilePath = join(modePath, 'handler.js');
100
+ } else {
101
+ feedback.build.error(Messages.build.error.invalid_preset_mode(mode, preset));
102
+ process.exit(1);
105
103
  }
106
104
 
105
+ configFilePath = new URL(`file://${configFilePath}`).href;
106
+ prebuildFilePath = new URL(`file://${prebuildFilePath}`).href;
107
+
107
108
  const config = (await import(configFilePath)).default;
108
109
  const prebuild = (await import(prebuildFilePath)).default;
109
110
  const handlerTemplate = readFileSync(handlerFilePath, 'utf-8');
@@ -123,10 +124,16 @@ async function loadBuildContext(preset, entry, mode) {
123
124
  const edgehooksPath = await getAliasPath('edge');
124
125
  newEntryContent = newEntryContent.replace('#edge', edgehooksPath);
125
126
 
126
- if (mode === 'server') {
127
- const filePath = join(process.cwd(), entry);
128
- const entryContent = readFileSync(filePath, 'utf-8');
129
- newEntryContent = newEntryContent.replace('__JS_CODE__', entryContent);
127
+ if ((preset === 'javascript' || preset === 'typescript') && (mode === 'compute')) {
128
+ try {
129
+ const filePath = join(process.cwd(), entry);
130
+ const entryContent = readFileSync(filePath, 'utf-8');
131
+ newEntryContent = newEntryContent.replace('__JS_CODE__', entryContent);
132
+ } catch (error) {
133
+ feedback.build.error(Messages.errors.file_doesnt_exist(entry));
134
+ debug.error(error);
135
+ process.exit(1);
136
+ }
130
137
  }
131
138
 
132
139
  newEntryContent = fixImportsAndRequestsPlace(newEntryContent);
@@ -140,6 +147,24 @@ async function loadBuildContext(preset, entry, mode) {
140
147
  return buildContext;
141
148
  }
142
149
 
150
+ /**
151
+ * Generates a build ID and saves it in the .env file (for deploy).
152
+ * @returns {Promise<string>} The generated build ID.
153
+ */
154
+ function generateBuildId() {
155
+ const projectRoot = process.cwd();
156
+ const outputPath = isWindows ? fileURLToPath(new URL(`file:///${join(projectRoot, '.edge')}`)) : join(projectRoot, '.edge');
157
+
158
+ const envFilePath = join(outputPath, '.env');
159
+ const BUILD_VERSION___AKA__VERSION_ID = generateTimestamp();
160
+ const envContent = `VERSION_ID=${BUILD_VERSION___AKA__VERSION_ID}`;
161
+
162
+ mkdirSync(outputPath, { recursive: true });
163
+ writeFileSync(envFilePath, envContent);
164
+
165
+ return BUILD_VERSION___AKA__VERSION_ID;
166
+ }
167
+
143
168
  /**
144
169
  * Class representing a Dispatcher for build operations.
145
170
  * @example
@@ -153,12 +178,14 @@ class Dispatcher {
153
178
  * @param {string} mode - The mode of build target.
154
179
  * @param {string} entry - The entry point for the build.
155
180
  * @param {string} versionId - The version ID for the build.
181
+ * @param {boolean} useNodePolyfills - The flag to indicates polyfills use.
156
182
  */
157
- constructor(preset, mode, entry, versionId) {
183
+ constructor(preset, mode, entry, versionId, useNodePolyfills) {
158
184
  this.preset = preset;
159
185
  this.mode = mode;
160
186
  this.entry = entry;
161
187
  this.versionId = versionId;
188
+ this.useNodePolyfills = useNodePolyfills;
162
189
  }
163
190
 
164
191
  /**
@@ -166,45 +193,68 @@ class Dispatcher {
166
193
  */
167
194
  run = async () => {
168
195
  // Load Context based on preset
169
- feedback.prebuild.info(Messages.build.info.prebuild_starting);
170
-
171
196
  const { entryContent, prebuild, config } = await loadBuildContext(
172
197
  this.preset,
173
198
  this.entry,
174
199
  this.mode,
175
200
  );
176
201
 
177
- // Run prebuild actions
178
- await prebuild(); // TODO: send context to prebuild
179
- feedback.prebuild.success(Messages.build.success.prebuild_succeeded);
180
- feedback.prebuild.info(Messages.build.info.vulcan_build_starting);
181
-
182
- // create tmp entrypoint
183
- const buildId = generateTimestamp(); // TODO: use versionID
184
- const currentDir = process.cwd();
185
- const tempBuilderEntryPath = join(currentDir, `vulcan-${buildId}.temp.js`);
186
-
187
- await writeFile(tempBuilderEntryPath, entryContent);
188
-
189
- // builder entry
190
- config.entry = tempBuilderEntryPath;
191
-
192
- let builder;
193
- switch (config.builder) {
194
- case 'webpack':
195
- builder = new Webpack(config, config.useNodePolyfills);
196
- break;
197
- default:
198
- builder = new Webpack(config, config.useNodePolyfills);
199
- break;
200
- }
202
+ const buildId = generateBuildId();
201
203
 
202
- // Run common build
203
- await builder.run();
204
+ const buildContext = {
205
+ preset: this.preset,
206
+ entry: this.entry,
207
+ mode: this.mode,
208
+ cliVersionId: this.versionId,
209
+ useNodePolyfills: this.useNodePolyfills,
210
+ buildId,
211
+ config,
212
+ entryContent,
213
+ };
204
214
 
205
- // delete .temp files
206
- rm(tempBuilderEntryPath);
207
- feedback.build.success(Messages.build.success.vulcan_build_succeeded);
215
+ // Run prebuild actions
216
+ try {
217
+ feedback.prebuild.info(Messages.build.info.prebuild_starting);
218
+ await prebuild(buildContext);
219
+ feedback.prebuild.success(Messages.build.success.prebuild_succeeded);
220
+
221
+ feedback.build.info(Messages.build.info.vulcan_build_starting);
222
+ // create tmp entrypoint
223
+ const currentDir = process.cwd();
224
+ let tempEntryFile = `vulcan-${buildId}.temp.`;
225
+ tempEntryFile += (this.preset === 'typescript') ? 'ts' : 'js';
226
+ const tempBuilderEntryPath = join(currentDir, tempEntryFile);
227
+
228
+ writeFileSync(tempBuilderEntryPath, entryContent);
229
+
230
+ // builder entry
231
+ config.entry = tempBuilderEntryPath;
232
+ config.buildId = buildId;
233
+ config.useNodePolyfills = this.useNodePolyfills;
234
+
235
+ let builder;
236
+ switch (config.builder) {
237
+ case 'webpack':
238
+ builder = new Webpack(config);
239
+ break;
240
+ case 'esbuild':
241
+ builder = new Esbuild(config);
242
+ break;
243
+ default:
244
+ builder = new Webpack(config);
245
+ break;
246
+ }
247
+
248
+ // Run common build
249
+ await builder.run();
250
+
251
+ // delete .temp files
252
+ rmSync(tempBuilderEntryPath);
253
+ feedback.build.success(Messages.build.success.vulcan_build_succeeded);
254
+ } catch (error) {
255
+ debug.error(error);
256
+ process.exit(1);
257
+ }
208
258
  };
209
259
  }
210
260
 
@@ -0,0 +1,51 @@
1
+ /**
2
+ * FrameworkInitializer contains various methods to initialize new projects
3
+ * in different JavaScript frameworks.
4
+ *
5
+ * Each method is an asynchronous function that takes a `projectName` as an argument.
6
+ * This `projectName` is then used to initialize a new project in the respective framework.
7
+ * @namespace FrameworkInitializer
8
+ * @typedef {object} FrameworkInitializer
9
+ * @property {Function} Angular - Initializes a new Angular project.
10
+ * @property {Function} Astro - Initializes a new Astro project.
11
+ * @property {Function} Hexo - Initializes a new Hexo project.
12
+ * @property {Function} Next - Initializes a new Next.js project.
13
+ * @property {Function} React - Initializes a new React project.
14
+ * @property {Function} Vue - Initializes a new Vue project.
15
+ * @property {Function} Vite - Initializes a new Vue project with Vite.
16
+ * @example
17
+ * const { Angular, React } = FrameworkInitializer;
18
+ *
19
+ * // Initialize a new Angular project called 'myAngularProject'
20
+ * await Angular('myAngularProject');
21
+ *
22
+ * // Initialize a new React project called 'myReactProject'
23
+ * await React('myReactProject');
24
+ */
25
+ import { exec } from '#utils';
26
+
27
+ const FrameworkInitializer = {
28
+ Angular: async (projectName) => {
29
+ await exec(`npx ng new ${projectName}`, 'Angular', false, true);
30
+ },
31
+ Astro: async (projectName) => {
32
+ await exec(`npx create-astro ${projectName}`, 'Astro', false, true);
33
+ },
34
+ Hexo: async (projectName) => {
35
+ await exec(`npx hexo init ${projectName}`, 'Hexo', false, true);
36
+ },
37
+ Next: async (projectName) => {
38
+ await exec(`npx create-next-app ${projectName}`, 'Next', false, true);
39
+ },
40
+ React: async (projectName) => {
41
+ await exec(`npx create-react-app ${projectName}`, 'React', false, true);
42
+ },
43
+ Vue: async (projectName) => {
44
+ await exec(`npx vue create ${projectName}`, 'Vue', false, true);
45
+ },
46
+ Vite: async (projectName) => {
47
+ await exec(`npx create-vue ${projectName}`, 'Vue/Vite', false, true);
48
+ },
49
+ };
50
+
51
+ export default FrameworkInitializer;
@@ -1,5 +1,8 @@
1
1
  import RuntimeApis from './runtime-apis.constants.js';
2
2
  import AzionEdges from './azion-edges.constants.js';
3
3
  import Messages from './messages/index.js';
4
+ import FrameworkInitializer from './framework-initializer.constants.js';
4
5
 
5
- export { AzionEdges, RuntimeApis, Messages };
6
+ export {
7
+ AzionEdges, RuntimeApis, Messages, FrameworkInitializer,
8
+ };