edge-functions 2.0.0 → 2.1.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/.commitlintrc.json +40 -0
- package/.husky/commit-msg +5 -0
- package/.husky/pre-commit +4 -0
- package/.prettierignore +2 -1
- package/CHANGELOG.md +62 -0
- package/jest.global.setup.js +20 -0
- package/lib/build/bundlers/esbuild/plugins/node-polyfills/index.js +10 -1
- package/lib/build/bundlers/esbuild/plugins/node-polyfills/node-pollyfills-paths.test.js +40 -0
- package/lib/build/dispatcher/dispatcher.js +21 -69
- package/lib/build/dispatcher/dispatcher.test.js +121 -8
- package/lib/build/dispatcher/helpers/helpers.js +64 -0
- package/lib/commands/build.commands.js +1 -1
- package/lib/commands/init.commands.js +48 -5
- package/lib/constants/framework-initializer.constants.js +100 -17
- package/lib/constants/index.js +11 -2
- package/lib/env/env.test.js +145 -0
- package/lib/env/polyfills/fetch.polyfills.test.js +46 -0
- package/lib/env/server.env.js +6 -6
- package/lib/env/vulcan.env.js +1 -1
- package/lib/presets/custom/astro/deliver/prebuild.js +7 -1
- package/lib/presets/custom/next/compute/config.js +3 -0
- package/lib/presets/custom/next/compute/node/index.js +22 -1
- package/lib/utils/generateManifest/generateManifest.utils.js +30 -0
- package/lib/utils/generateManifest/index.js +3 -0
- package/lib/utils/generateWebpackBanner/generateWebpackBanner.utils.test.js +22 -0
- package/lib/utils/getExportedFunctionBody/getExportedFunctionBody.utils.test.js +2 -1
- package/lib/utils/getUrlFromResource/getUrlFromResource.utils.test.js +43 -0
- package/lib/utils/getVulcanBuildId/getVulcanBuildId.utils.test.js +5 -25
- package/lib/utils/index.js +2 -0
- package/lib/utils/injectFilesInMem/injectFilesInMem.utils.test.js +2 -2
- package/lib/utils/relocateImportsAndRequires/relocateImportsAndRequires.utils.test.js +43 -0
- package/lib/utils/vercel/vercel.utils.test.js +110 -0
- package/package.json +21 -4
- package/verdaccio/config/config.yaml +50 -0
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
import { exec } from '#utils';
|
|
2
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
const FrameworksDefaultVersions = {
|
|
6
|
+
Angular: {
|
|
7
|
+
options: [{ value: 'latest', message: 'static supported' }],
|
|
8
|
+
},
|
|
9
|
+
Astro: {
|
|
10
|
+
options: [{ value: 'latest', message: 'static supported' }],
|
|
11
|
+
},
|
|
12
|
+
Hexo: {
|
|
13
|
+
options: [{ value: 'latest', message: 'static supported' }],
|
|
14
|
+
},
|
|
15
|
+
Next: {
|
|
16
|
+
options: [
|
|
17
|
+
{ value: '12.3.1', message: 'SSR supported' },
|
|
18
|
+
{ value: 'latest', message: 'static supported' },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
React: {
|
|
22
|
+
options: [{ value: 'latest', message: 'static supported' }],
|
|
23
|
+
},
|
|
24
|
+
Vue: {
|
|
25
|
+
options: [{ value: 'latest', message: 'static supported' }],
|
|
26
|
+
},
|
|
27
|
+
Vite: {
|
|
28
|
+
options: [{ value: 'latest', message: 'static supported' }],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
1
31
|
/**
|
|
2
32
|
* FrameworkInitializer contains various methods to initialize new projects
|
|
3
33
|
* in different JavaScript frameworks.
|
|
@@ -22,30 +52,83 @@
|
|
|
22
52
|
* // Initialize a new React project called 'myReactProject'
|
|
23
53
|
* await React('myReactProject');
|
|
24
54
|
*/
|
|
25
|
-
import { exec } from '#utils';
|
|
26
|
-
|
|
27
55
|
const FrameworkInitializer = {
|
|
28
|
-
|
|
29
|
-
|
|
56
|
+
JavaScript: async (projectName) => {
|
|
57
|
+
const projectPath = join(process.cwd(), projectName);
|
|
58
|
+
mkdirSync(projectPath);
|
|
59
|
+
|
|
60
|
+
const workerContent = `
|
|
61
|
+
export default function myWorker(event) {
|
|
62
|
+
return new Response('Hello World');
|
|
63
|
+
}
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
writeFileSync(join(projectPath, 'main.js'), workerContent.trim());
|
|
67
|
+
},
|
|
68
|
+
TypeScript: async (projectName) => {
|
|
69
|
+
const projectPath = join(process.cwd(), projectName);
|
|
70
|
+
mkdirSync(projectPath);
|
|
71
|
+
|
|
72
|
+
const content = `
|
|
73
|
+
export default function myWorker(event: FetchEvent): Response {
|
|
74
|
+
return new Response('Hello World');
|
|
75
|
+
}`;
|
|
76
|
+
const vulcanFile = `preset=typescript\nentry=main.ts\n`;
|
|
77
|
+
|
|
78
|
+
writeFileSync(join(projectPath, '.vulcan'), vulcanFile);
|
|
79
|
+
writeFileSync(join(projectPath, 'main.ts'), content.trim());
|
|
80
|
+
},
|
|
81
|
+
Angular: async (projectName, version = FrameworksDefaultVersions.Angular) => {
|
|
82
|
+
await exec(
|
|
83
|
+
`npx @angular/cli@${version} new ${projectName}`,
|
|
84
|
+
'Angular',
|
|
85
|
+
false,
|
|
86
|
+
true,
|
|
87
|
+
);
|
|
30
88
|
},
|
|
31
|
-
Astro: async (projectName) => {
|
|
32
|
-
await exec(
|
|
89
|
+
Astro: async (projectName, version = FrameworksDefaultVersions.Astro) => {
|
|
90
|
+
await exec(
|
|
91
|
+
`npx create-astro@${version} ${projectName}`,
|
|
92
|
+
'Astro',
|
|
93
|
+
false,
|
|
94
|
+
true,
|
|
95
|
+
);
|
|
33
96
|
},
|
|
34
|
-
Hexo: async (projectName) => {
|
|
35
|
-
await exec(`npx hexo init ${projectName}`, 'Hexo', false, true);
|
|
97
|
+
Hexo: async (projectName, version = FrameworksDefaultVersions.Hexo) => {
|
|
98
|
+
await exec(`npx hexo@${version} init ${projectName}`, 'Hexo', false, true);
|
|
36
99
|
},
|
|
37
|
-
Next: async (projectName) => {
|
|
38
|
-
await exec(
|
|
100
|
+
Next: async (projectName, version = FrameworksDefaultVersions.Next) => {
|
|
101
|
+
await exec(
|
|
102
|
+
`npx create-next-app@${version} ${projectName} && cd ${projectName} && npm i next@${version}`,
|
|
103
|
+
'Next',
|
|
104
|
+
false,
|
|
105
|
+
true,
|
|
106
|
+
);
|
|
39
107
|
},
|
|
40
|
-
React: async (projectName) => {
|
|
41
|
-
await exec(
|
|
108
|
+
React: async (projectName, version = FrameworksDefaultVersions.React) => {
|
|
109
|
+
await exec(
|
|
110
|
+
`npx create-react-app@${version} ${projectName}`,
|
|
111
|
+
'React',
|
|
112
|
+
false,
|
|
113
|
+
true,
|
|
114
|
+
);
|
|
42
115
|
},
|
|
43
|
-
Vue: async (projectName) => {
|
|
44
|
-
await exec(
|
|
116
|
+
Vue: async (projectName, version = FrameworksDefaultVersions.Vue) => {
|
|
117
|
+
await exec(
|
|
118
|
+
`npx @vue/cli@${version} create ${projectName}`,
|
|
119
|
+
'Vue',
|
|
120
|
+
false,
|
|
121
|
+
true,
|
|
122
|
+
);
|
|
45
123
|
},
|
|
46
|
-
Vite: async (projectName) => {
|
|
47
|
-
await exec(
|
|
124
|
+
Vite: async (projectName, version = FrameworksDefaultVersions.Vite) => {
|
|
125
|
+
await exec(
|
|
126
|
+
`npx create-vue@${version} ${projectName}`,
|
|
127
|
+
'Vue/Vite',
|
|
128
|
+
false,
|
|
129
|
+
true,
|
|
130
|
+
);
|
|
48
131
|
},
|
|
49
132
|
};
|
|
50
133
|
|
|
51
|
-
export
|
|
134
|
+
export { FrameworkInitializer, FrameworksDefaultVersions };
|
package/lib/constants/index.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
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
|
|
4
|
+
import {
|
|
5
|
+
FrameworkInitializer,
|
|
6
|
+
FrameworksDefaultVersions,
|
|
7
|
+
} from './framework-initializer.constants.js';
|
|
5
8
|
|
|
6
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
AzionEdges,
|
|
11
|
+
RuntimeApis,
|
|
12
|
+
Messages,
|
|
13
|
+
FrameworkInitializer,
|
|
14
|
+
FrameworksDefaultVersions,
|
|
15
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect } from '@jest/globals';
|
|
2
|
+
import mockFs from 'mock-fs';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import runtime from './runtime.env.js';
|
|
5
|
+
import vulcanEnv from './vulcan.env.js';
|
|
6
|
+
|
|
7
|
+
describe('runtime env', () => {
|
|
8
|
+
it('Should instantiate a edge runtime', () => {
|
|
9
|
+
const code = `
|
|
10
|
+
addEventListener('fetch', event => {
|
|
11
|
+
const { searchParams } = new URL(event.request.url)
|
|
12
|
+
const url = searchParams.get('url')
|
|
13
|
+
return event.respondWith(fetch(url))
|
|
14
|
+
})`;
|
|
15
|
+
const edgeRuntime = runtime(code);
|
|
16
|
+
|
|
17
|
+
expect(edgeRuntime).toBeDefined();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('vulcan env', () => {
|
|
22
|
+
const { env } = process;
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.resetModules();
|
|
25
|
+
process.env = { HOME: '/home/user' };
|
|
26
|
+
process.cwd = jest.fn(() => '/');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
process.env = env;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('Should create a vulcan env with global scope', async () => {
|
|
34
|
+
mockFs({});
|
|
35
|
+
await vulcanEnv.createVulcanEnv(
|
|
36
|
+
{ API_KEY: 'abc123', ANOTHER_KEY: 'xyz' },
|
|
37
|
+
'global',
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const vulcanEnvContent = fs.readFileSync(
|
|
41
|
+
'/home/user/.azion/.vulcan',
|
|
42
|
+
'utf8',
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
expect(vulcanEnvContent.trim()).toEqual(
|
|
46
|
+
`API_KEY=abc123
|
|
47
|
+
ANOTHER_KEY=xyz`,
|
|
48
|
+
);
|
|
49
|
+
mockFs.restore();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Should create a vulcan env with default scope', async () => {
|
|
53
|
+
mockFs({});
|
|
54
|
+
await vulcanEnv.createVulcanEnv({ API_KEY: 'abc123', ANOTHER_KEY: 'xyz' });
|
|
55
|
+
|
|
56
|
+
const vulcanEnvContent = fs.readFileSync(
|
|
57
|
+
'/home/user/.azion/.vulcan',
|
|
58
|
+
'utf8',
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(vulcanEnvContent.trim()).toEqual(
|
|
62
|
+
`API_KEY=abc123
|
|
63
|
+
ANOTHER_KEY=xyz`,
|
|
64
|
+
);
|
|
65
|
+
mockFs.restore();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('Should create a vulcan env with local scope', async () => {
|
|
69
|
+
mockFs({});
|
|
70
|
+
await vulcanEnv.createVulcanEnv(
|
|
71
|
+
{ API_KEY: 'abc123', ANOTHER_KEY: 'xyz' },
|
|
72
|
+
'local',
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const vulcanEnvContent = fs.readFileSync('/.vulcan', 'utf8');
|
|
76
|
+
|
|
77
|
+
expect(vulcanEnvContent.trim()).toEqual(
|
|
78
|
+
`API_KEY=abc123
|
|
79
|
+
ANOTHER_KEY=xyz`,
|
|
80
|
+
);
|
|
81
|
+
mockFs.restore();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('Should update a vulcan env with local scope', async () => {
|
|
85
|
+
mockFs({
|
|
86
|
+
'/.vulcan': `API_KEY=abc123`,
|
|
87
|
+
});
|
|
88
|
+
await vulcanEnv.createVulcanEnv({ API_KEY: 'abc456' }, 'local');
|
|
89
|
+
|
|
90
|
+
const vulcanEnvContent = fs.readFileSync('/.vulcan', 'utf8');
|
|
91
|
+
|
|
92
|
+
expect(vulcanEnvContent.trim()).toEqual(`API_KEY=abc456`);
|
|
93
|
+
mockFs.restore();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('Should read a vulcan env with default scope', async () => {
|
|
97
|
+
mockFs({
|
|
98
|
+
'/home/user/.azion/.vulcan': `API_KEY=abc123`,
|
|
99
|
+
});
|
|
100
|
+
const envContent = await vulcanEnv.readVulcanEnv();
|
|
101
|
+
|
|
102
|
+
expect(envContent).toMatchObject({ API_KEY: 'abc123' });
|
|
103
|
+
mockFs.restore();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('Should read a vulcan env with global scope', async () => {
|
|
107
|
+
mockFs({
|
|
108
|
+
'/home/user/.azion/.vulcan': `API_KEY=abc123`,
|
|
109
|
+
});
|
|
110
|
+
const envContent = await vulcanEnv.readVulcanEnv('global');
|
|
111
|
+
|
|
112
|
+
expect(envContent).toMatchObject({ API_KEY: 'abc123' });
|
|
113
|
+
mockFs.restore();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('Should read a vulcan env with local scope', async () => {
|
|
117
|
+
mockFs({
|
|
118
|
+
'/.vulcan': `API_KEY=abc123`,
|
|
119
|
+
});
|
|
120
|
+
const envContent = await vulcanEnv.readVulcanEnv('local');
|
|
121
|
+
|
|
122
|
+
expect(envContent).toMatchObject({ API_KEY: 'abc123' });
|
|
123
|
+
mockFs.restore();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('Should read a vulcanconfig file', async () => {
|
|
127
|
+
mockFs({
|
|
128
|
+
'/vulcan.config.js': `module.exports = {
|
|
129
|
+
memoryFS: {
|
|
130
|
+
injectionDirs: ['.faststore/@generated/graphql'],
|
|
131
|
+
removePathPrefix: '.faststore/',
|
|
132
|
+
}
|
|
133
|
+
};`,
|
|
134
|
+
});
|
|
135
|
+
const expectedContent = {
|
|
136
|
+
memoryFS: {
|
|
137
|
+
injectionDirs: ['.faststore/@generated/graphql'],
|
|
138
|
+
removePathPrefix: '.faststore/',
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
const vulcaConfigFileContent = await vulcanEnv.loadVulcanConfigFile();
|
|
142
|
+
expect(vulcaConfigFileContent).toEqual(expectedContent);
|
|
143
|
+
mockFs.restore();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import mockFS from 'mock-fs';
|
|
2
|
+
import { Headers, Response, Request, URL } from '@edge-runtime/primitives';
|
|
3
|
+
import { expect } from '@jest/globals';
|
|
4
|
+
import fetchPolyfill from './fetch.polyfills.js';
|
|
5
|
+
|
|
6
|
+
describe('fetchPolyfill', () => {
|
|
7
|
+
it('should call the global fetch function for non-file URLs', async () => {
|
|
8
|
+
const resource = 'https://example.com/api/data';
|
|
9
|
+
const options = { method: 'GET' };
|
|
10
|
+
const mockContext = {
|
|
11
|
+
Headers,
|
|
12
|
+
Response,
|
|
13
|
+
Request,
|
|
14
|
+
URL,
|
|
15
|
+
RESERVED_FETCH: () => {
|
|
16
|
+
const response = '{ "statusText": "Not Found" }';
|
|
17
|
+
return JSON.parse(response);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const response = await fetchPolyfill(mockContext, resource, options);
|
|
22
|
+
|
|
23
|
+
expect(response.statusText).toBe('Not Found');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return a response when the begin with file://', async () => {
|
|
27
|
+
mockFS({
|
|
28
|
+
'.edge': {
|
|
29
|
+
'.env': 'VERSION_ID=123456',
|
|
30
|
+
storage: {
|
|
31
|
+
data: { build: { 'file.js': "console.log('ops')" } },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const resource = 'file:///data/build/file.js';
|
|
37
|
+
const options = { method: 'GET' };
|
|
38
|
+
const mockContext = { Headers, Response };
|
|
39
|
+
|
|
40
|
+
const response = await fetchPolyfill(mockContext, resource, options);
|
|
41
|
+
|
|
42
|
+
expect(response.headers.get('Content-Type')).toBe('application/javascript');
|
|
43
|
+
expect(response.status).toBe(200);
|
|
44
|
+
mockFS.restore();
|
|
45
|
+
});
|
|
46
|
+
});
|
package/lib/env/server.env.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { debug, readWorkerFile, feedback, exec } from '#utils';
|
|
2
2
|
import { Messages } from '#constants';
|
|
3
|
-
import
|
|
3
|
+
import { runServer, EdgeRuntime } from 'edge-runtime';
|
|
4
4
|
import chokidar from 'chokidar';
|
|
5
5
|
import runtime from './runtime.env.js';
|
|
6
6
|
import vulcan from './vulcan.env.js';
|
|
7
7
|
|
|
8
|
-
const { runServer, EdgeRuntimeServer } = edgeRuntimePackage;
|
|
9
|
-
|
|
10
8
|
let currentServer;
|
|
11
9
|
let isChangeHandlerRunning = false;
|
|
12
10
|
|
|
@@ -32,11 +30,11 @@ async function readWorkerCode(workerPath) {
|
|
|
32
30
|
* Initialize and run the server with the given port and worker code.
|
|
33
31
|
* @param {number} port - The port number.
|
|
34
32
|
* @param {string} workerCode - The worker code.
|
|
35
|
-
* @returns {Promise<
|
|
33
|
+
* @returns {Promise<EdgeRuntime>} - The initialized server.
|
|
36
34
|
*/
|
|
37
35
|
async function initializeServer(port, workerCode) {
|
|
38
36
|
const execution = runtime(workerCode);
|
|
39
|
-
return runServer({ port, host: '
|
|
37
|
+
return runServer({ port, host: '0.0.0.0', runtime: execution });
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
/**
|
|
@@ -55,7 +53,9 @@ async function manageServer(workerPath, port) {
|
|
|
55
53
|
try {
|
|
56
54
|
currentServer = await initializeServer(port, workerCode);
|
|
57
55
|
feedback.server.success(
|
|
58
|
-
Messages.env.server.success.server_running(
|
|
56
|
+
Messages.env.server.success.server_running(
|
|
57
|
+
`0.0.0.0:${port}, url: http://localhost:${port}`,
|
|
58
|
+
),
|
|
59
59
|
);
|
|
60
60
|
} catch (error) {
|
|
61
61
|
if (error.code === 'EADDRINUSE') {
|
package/lib/env/vulcan.env.js
CHANGED
|
@@ -147,7 +147,7 @@ async function loadVulcanConfigFile() {
|
|
|
147
147
|
let vulcanCustomConfig = null;
|
|
148
148
|
|
|
149
149
|
if (fs.existsSync(buildConfigPath)) {
|
|
150
|
-
const vulcanCustomConfigModule = await import(
|
|
150
|
+
const vulcanCustomConfigModule = await import(buildConfigPath);
|
|
151
151
|
vulcanCustomConfig = vulcanCustomConfigModule.default || {};
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { rm, readFile } from 'fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
exec,
|
|
4
|
+
getPackageManager,
|
|
5
|
+
copyDirectory,
|
|
6
|
+
generateManifest,
|
|
7
|
+
} from '#utils';
|
|
3
8
|
|
|
4
9
|
const packageManager = await getPackageManager();
|
|
5
10
|
|
|
@@ -25,6 +30,7 @@ async function prebuild() {
|
|
|
25
30
|
|
|
26
31
|
// move files to vulcan default path
|
|
27
32
|
copyDirectory(outDir, newOutDir);
|
|
33
|
+
generateManifest('*', '*', 'deliver');
|
|
28
34
|
rm(outDir, { recursive: true, force: true });
|
|
29
35
|
}
|
|
30
36
|
|
|
@@ -68,6 +68,9 @@ const config = {
|
|
|
68
68
|
async_hooks: false,
|
|
69
69
|
tls: false,
|
|
70
70
|
net: false,
|
|
71
|
+
child_process: false,
|
|
72
|
+
https: require.resolve('https-browserify'),
|
|
73
|
+
tty: require.resolve('tty-browserify'),
|
|
71
74
|
http: require.resolve('stream-http'),
|
|
72
75
|
buffer: require.resolve('buffer/'),
|
|
73
76
|
crypto: require.resolve('crypto-browserify/'),
|
|
@@ -5,6 +5,22 @@ import fs from 'fs';
|
|
|
5
5
|
import { copyDirectory, feedback, getAbsoluteLibDirPath } from '#utils';
|
|
6
6
|
import BuildStatic from './prebuild/index.js';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* If a relative path exists, copy public path to root
|
|
10
|
+
* @param {string} pathPrefix - prefix
|
|
11
|
+
* @param {string} rootDir - application root dir
|
|
12
|
+
*/
|
|
13
|
+
function handlePublicDir(pathPrefix, rootDir) {
|
|
14
|
+
const validPathPrefix =
|
|
15
|
+
pathPrefix && typeof pathPrefix === 'string' && pathPrefix !== '';
|
|
16
|
+
|
|
17
|
+
if (validPathPrefix) {
|
|
18
|
+
const srcPublicDir = path.resolve(pathPrefix, 'public');
|
|
19
|
+
const destPublicDir = path.resolve(rootDir, 'public');
|
|
20
|
+
copyDirectory(srcPublicDir, destPublicDir);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* Run actions to build next for node runtime.
|
|
10
26
|
* @param {string} nextVersion - project next version in package.json
|
|
@@ -50,10 +66,15 @@ async function run(nextVersion, buildContext) {
|
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
// STATICS
|
|
69
|
+
// copy to root public dir if necessary
|
|
70
|
+
if (buildContext.memoryFS) {
|
|
71
|
+
handlePublicDir(buildContext.memoryFS.removePathPrefix, rootDir);
|
|
72
|
+
}
|
|
73
|
+
|
|
53
74
|
const buildStatic = new BuildStatic({
|
|
54
75
|
rootDir,
|
|
55
76
|
includeDirs: ['./.next', './public'],
|
|
56
|
-
staticDirs: ['public', '.next/static'],
|
|
77
|
+
staticDirs: ['./public', '.next/static'],
|
|
57
78
|
excludeDirs: ['./.next/cache', 'node_modules'],
|
|
58
79
|
out: OUT_DIR_CUSTOM_SERVER,
|
|
59
80
|
versionId: buildContext.buildId,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { writeFileSync } from 'fs';
|
|
3
|
+
import { Utils } from '#namespaces';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @function
|
|
7
|
+
* @memberof Utils
|
|
8
|
+
* @description Generates manifest object and writes it to a file.
|
|
9
|
+
* @param {string} route - the route to be used, or all represented by '*'
|
|
10
|
+
* @param {string} filePath - the file path for the route, or all represented by '*'
|
|
11
|
+
* @param {string} mode - The mode of the operation, either 'compute', 'deliver', or both represented by '*'.
|
|
12
|
+
*/
|
|
13
|
+
function generateManifest(route, filePath, mode) {
|
|
14
|
+
const manifestPath = join(process.cwd(), '.edge/manifest.json');
|
|
15
|
+
const manifest = { routes: {} };
|
|
16
|
+
|
|
17
|
+
// Check the mode and add the route to the manifest appropriately.
|
|
18
|
+
if (mode === 'compute' || mode === 'deliver' || mode === '*') {
|
|
19
|
+
manifest.routes[mode] = {};
|
|
20
|
+
manifest.routes[mode][route] = filePath;
|
|
21
|
+
} else {
|
|
22
|
+
throw new Error('Invalid mode. Must be "compute", "deliver", or "*".');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Write the new manifest back to the file.
|
|
26
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
|
|
27
|
+
console.log(`New manifest created with ${mode} information.`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default generateManifest;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import mockFS from 'mock-fs';
|
|
2
|
+
import generateWebpackBanner from './generateWebpackBanner.utils.js';
|
|
3
|
+
|
|
4
|
+
describe('generateWebpackBanner', () => {
|
|
5
|
+
it('should generate a webpack banner', () => {
|
|
6
|
+
const arrayOfPaths = ['path/to/file1.js', 'path/to/file2.js'];
|
|
7
|
+
const expectedBanner = 'file-1-content\nfile-2-content\n';
|
|
8
|
+
mockFS({
|
|
9
|
+
path: {
|
|
10
|
+
to: {
|
|
11
|
+
'file1.js': 'file-1-content',
|
|
12
|
+
'file2.js': 'file-2-content',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const bannerArray = generateWebpackBanner(arrayOfPaths);
|
|
18
|
+
|
|
19
|
+
expect(bannerArray).toBe(expectedBanner);
|
|
20
|
+
mockFS.restore();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
/* eslint-disable jest/no-disabled-tests */
|
|
1
2
|
import getExportedFunctionBody from './getExportedFunctionBody.utils.js';
|
|
2
3
|
|
|
3
|
-
describe('getExportedFunctionBody', () => {
|
|
4
|
+
describe.skip('getExportedFunctionBody', () => {
|
|
4
5
|
it('should extract the body from a default exported function declaration', () => {
|
|
5
6
|
const inputCode = `
|
|
6
7
|
export default function test() {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { URL, Request } from '@edge-runtime/primitives';
|
|
2
|
+
import getUrlFromResource from './getUrlFromResource.utils.js';
|
|
3
|
+
|
|
4
|
+
describe('getUrlFromResource', () => {
|
|
5
|
+
it('should return a URL when passed a valid string', () => {
|
|
6
|
+
const urlString = 'https://example.com/';
|
|
7
|
+
const context = { Request, URL };
|
|
8
|
+
const result = getUrlFromResource(context, urlString);
|
|
9
|
+
expect(result).toBeInstanceOf(URL);
|
|
10
|
+
expect(result.href).toBe(urlString);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should return a URL when passed a Request object', () => {
|
|
14
|
+
const request = new Request('https://example.com');
|
|
15
|
+
const context = { Request, URL };
|
|
16
|
+
const result = getUrlFromResource(context, request);
|
|
17
|
+
expect(result).toBeInstanceOf(URL);
|
|
18
|
+
expect(result.href).toBe(request.url);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return the same URL when passed a URL object', () => {
|
|
22
|
+
const url = new URL('https://example.com');
|
|
23
|
+
const context = { Request, URL };
|
|
24
|
+
const result = getUrlFromResource(context, url);
|
|
25
|
+
expect(result).toBe(url);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should throw an error when passed an invalid url', () => {
|
|
29
|
+
const invalidInput = 'example.com'; // Invalid input (not a string, Request, or URL)
|
|
30
|
+
const context = { Request, URL };
|
|
31
|
+
expect(() => getUrlFromResource(context, invalidInput)).toThrow(
|
|
32
|
+
'Invalid URL',
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should throw an error when passed an invalid input', () => {
|
|
37
|
+
const invalidInput = 123; // Invalid input (not a string, Request, or URL)
|
|
38
|
+
const context = { Request, URL };
|
|
39
|
+
expect(() => getUrlFromResource(context, invalidInput)).toThrow(
|
|
40
|
+
"Invalid resource input. 'resource' must be 'URL', 'Request' or 'string'.",
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -1,36 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { tmpdir } from 'os';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
|
|
1
|
+
import mockFs from 'mock-fs';
|
|
5
2
|
import getVulcanBuildId from './index.js';
|
|
6
3
|
|
|
7
|
-
const FILE_NAME = '.env';
|
|
8
|
-
const FILE_DIR = '.edge';
|
|
9
|
-
const CURRENT_DIR = process.cwd();
|
|
10
|
-
const TMP_DIR = tmpdir();
|
|
11
|
-
const DIR_PATH = join(TMP_DIR, FILE_DIR);
|
|
12
|
-
const FILE_PATH = join(TMP_DIR, FILE_DIR, FILE_NAME);
|
|
13
|
-
|
|
14
4
|
describe('getVulcanBuildId utils', () => {
|
|
15
|
-
beforeAll(() => {
|
|
16
|
-
process.chdir(TMP_DIR);
|
|
17
|
-
|
|
18
|
-
mkdirSync(DIR_PATH);
|
|
19
|
-
|
|
20
|
-
writeFileSync(FILE_PATH, 'VERSION_ID=20230627142534');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
afterAll(() => {
|
|
24
|
-
process.chdir(CURRENT_DIR);
|
|
25
|
-
|
|
26
|
-
rmSync(DIR_PATH, { recursive: true, force: true });
|
|
27
|
-
});
|
|
28
|
-
|
|
29
5
|
test('Should fetch the unique build ID for the current project', async () => {
|
|
6
|
+
mockFs({
|
|
7
|
+
'.edge': { '.env': 'VERSION_ID=20230627142534' },
|
|
8
|
+
});
|
|
30
9
|
const expectedOutput = '20230627142534';
|
|
31
10
|
|
|
32
11
|
const result = getVulcanBuildId();
|
|
33
12
|
|
|
34
13
|
expect(result).toBe(expectedOutput);
|
|
14
|
+
mockFs.restore();
|
|
35
15
|
});
|
|
36
16
|
});
|
package/lib/utils/index.js
CHANGED
|
@@ -18,6 +18,7 @@ import generateWebpackBanner from './generateWebpackBanner/index.js';
|
|
|
18
18
|
import relocateImportsAndRequires from './relocateImportsAndRequires/index.js';
|
|
19
19
|
import getExportedFunctionBody from './getExportedFunctionBody/index.js';
|
|
20
20
|
import injectFilesInMem from './injectFilesInMem/index.js';
|
|
21
|
+
import generateManifest from './generateManifest/index.js';
|
|
21
22
|
|
|
22
23
|
export {
|
|
23
24
|
copyDirectory,
|
|
@@ -40,4 +41,5 @@ export {
|
|
|
40
41
|
generateWebpackBanner,
|
|
41
42
|
relocateImportsAndRequires,
|
|
42
43
|
injectFilesInMem,
|
|
44
|
+
generateManifest,
|
|
43
45
|
};
|
|
@@ -26,10 +26,10 @@ describe('injectFilesInMem', () => {
|
|
|
26
26
|
'/path/to/dir2',
|
|
27
27
|
]);
|
|
28
28
|
|
|
29
|
-
expect(codeToInject).toContain('globalThis.__FILES__');
|
|
29
|
+
expect(codeToInject).toContain('globalThis.vulcan.__FILES__');
|
|
30
30
|
|
|
31
31
|
const strData = codeToInject
|
|
32
|
-
.replace('globalThis.__FILES__=', '')
|
|
32
|
+
.replace('globalThis.vulcan.__FILES__=', '')
|
|
33
33
|
.replace('};', '}');
|
|
34
34
|
const data = JSON.parse(strData);
|
|
35
35
|
|