Skip to content

Commit 2fbc5f1

Browse files
skyoctmaslow
andauthored
feat(runtime): detach custom dependency, support node_module caching (#1658)
* feat: add custom dep path * chore: remove log4js from runtime, allow adding dup npm deps * chore: rm unused imports * fix(runtime): support custom dep path in import() * chore: merge upstream main * fix(runtime): add --experimental-vm-modules for runtime * feat(runtime): support node_modules cache in init scripts * fix(runtime): fix download error in init script * feat(server): support node_modules cache in server --------- Co-authored-by: maslow <[email protected]>
1 parent eb35c59 commit 2fbc5f1

22 files changed

+9013
-1696
lines changed

.vscode/settings.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"Chakra",
4242
"chatgpt",
4343
"ciphertext",
44+
"cloudbin",
4445
"clsx",
4546
"coll",
4647
"compat",
@@ -105,6 +106,7 @@
105106
"statefulset",
106107
"storageclass",
107108
"Streamable",
109+
"stylelint",
108110
"tailwindcss",
109111
"tanstack",
110112
"telepresence",
@@ -125,8 +127,7 @@
125127
"withs",
126128
"xmlparser",
127129
"zcube",
128-
"zustand",
129-
"stylelint"
130+
"zustand"
130131
],
131132
"i18n-ally.localesPaths": "web/public/locales",
132133
"i18n-ally.enabledParsers": [

runtimes/nodejs/Dockerfile.init

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
FROM lafyun/runtime-node:latest
1+
FROM node:20
22

3-
CMD [ "sh", "/app/init.sh" ]
3+
WORKDIR /app
4+
5+
COPY ./init.sh /app/init.sh
6+
7+
CMD [ "sh", "/app/init.sh" ]

runtimes/nodejs/init.sh

+96-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,108 @@
11
#!/bin/sh
22

33
set -e
4-
# node ./dist/init.js
54

65
# skip init if $DEPENDENCIES is empty
76
if [ -z "$DEPENDENCIES" ]; then
87
echo "No dependencies to install."
9-
cp -r /app/* /tmp/app
108
exit 0
119
fi
1210

11+
# if $NODE_MODULES_URL is not empty
12+
if [ -n "$NODE_MODULES_PULL_URL" ]; then
13+
echo "Downloading node_modules from $NODE_MODULES_PULL_URL"
14+
15+
# get start time
16+
start_time=$(date +%s)
17+
18+
# temporarily disable set -e
19+
set +e
20+
21+
# download node_modules.tar and untar to `node_modules`
22+
curl -sSfL $NODE_MODULES_PULL_URL -o node_modules.tar
23+
24+
end_time=$(date +%s)
25+
26+
# if error
27+
if [ $? -ne 0 ]; then
28+
echo "Failed to download node_modules cache."
29+
else
30+
elapsed_time=$(expr $end_time - $start_time)
31+
echo "Downloaded node_modules.tar in $elapsed_time seconds."
32+
fi
33+
34+
# untar node_modules.tar
35+
tar -xf node_modules.tar -C .
36+
37+
# check tar exit code
38+
if [ $? -ne 0 ]; then
39+
echo "Failed to extract node_modules cache."
40+
else
41+
end_time_2=$(date +%s)
42+
elapsed_time_2=$(expr $end_time_2 - $end_time)
43+
echo "Extracted node_modules cache in $elapsed_time_2 seconds."
44+
fi
45+
46+
# re-enable set -e
47+
set -e
48+
else
49+
echo "No node_modules cache found, continuing installation."
50+
fi
51+
52+
CACHED_DEPENDENCIES=""
53+
# if node_modules/.dependencies exists
54+
if [ -f "node_modules/.dependencies" ]; then
55+
CACHED_DEPENDENCIES=`cat node_modules/.dependencies`
56+
fi
57+
58+
echo "Cached dependencies: $CACHED_DEPENDENCIES"
59+
echo "Dependencies to install: $DEPENDENCIES"
60+
61+
# if $CACHED_DEPENDENCIES is equal to $DEPENDENCIES
62+
if [ "$CACHED_DEPENDENCIES" = "$DEPENDENCIES" ]; then
63+
echo "No dependencies changed since last cache build."
64+
exit 0
65+
else
66+
echo "Dependencies changed since last cache build."
67+
fi
68+
69+
70+
# npm install $DEPENDENCIES
71+
start_time=$(date +%s)
1372
echo "npm install $DEPENDENCIES $NPM_INSTALL_FLAGS"
1473
npm install $DEPENDENCIES $NPM_INSTALL_FLAGS
15-
cp -r /app/* /tmp/app
74+
end_time=$(date +%s)
75+
elapsed_time=$(expr $end_time - $start_time)
76+
echo "Installed dependencies in $elapsed_time seconds."
77+
78+
# if $NODE_MODULES_PUSH_URL is not empty
79+
if [ -n "$NODE_MODULES_PUSH_URL" ]; then
80+
# temporarily disable set -e
81+
set +e
82+
83+
start_time=$(date +%s)
84+
echo $DEPENDENCIES > node_modules/.dependencies
85+
echo "Uploading node_modules to $NODE_MODULES_PUSH_URL"
86+
87+
# tar `node_modules` to node_modules.tar
88+
tar -cf node_modules.tar ./node_modules
89+
90+
end_time_1=$(date +%s)
91+
elapsed_time=$(expr $end_time_1 - $start_time)
92+
echo "Compressed node_modules in $elapsed_time seconds."
93+
94+
# upload node_modules.tar to $NODE_MODULES_PUSH_URL
95+
curl -sSfL -X PUT -T node_modules.tar $NODE_MODULES_PUSH_URL
96+
97+
98+
if [ $? -ne 0 ]; then
99+
echo "Failed to upload node_modules cache."
100+
else
101+
end_time_2=$(date +%s)
102+
elapsed_time_2=$(expr $end_time_2 - $end_time)
103+
echo "Uploaded node_modules.tar in $elapsed_time_2 seconds."
104+
fi
105+
106+
# re-enable set -e
107+
set -e
108+
fi

runtimes/nodejs/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"express-xml-bodyparser": "^0.3.0",
4545
"jsonwebtoken": "^9.0.0",
4646
"lodash": "^4.17.21",
47-
"log4js": "^6.7.1",
4847
"minio": "^7.0.32",
4948
"mongodb": "^4.12.1",
5049
"mongodb-uri": "^0.9.7",

runtimes/nodejs/src/config.ts

+4
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,8 @@ export default class Config {
109109
static get DISABLE_MODULE_CACHE(): boolean {
110110
return process.env.DISABLE_MODULE_CACHE === 'true'
111111
}
112+
113+
static get CUSTOM_DEPENDENCY_BASE_PATH(): string {
114+
return process.env.CUSTOM_DEPENDENCY_BASE_PATH || '/tmp/custom_dependency'
115+
}
112116
}

runtimes/nodejs/src/db.ts

+27-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,32 @@
88
import { LoggerInterface, MongoAccessor } from 'database-proxy'
99
import Config from './config'
1010
import * as mongodb_uri from 'mongodb-uri'
11-
import * as log4js from 'log4js'
1211
import { logger } from './support/logger'
1312

13+
14+
// Define a noop logger for mongo accessor
15+
class AccessorLogger implements LoggerInterface {
16+
level: number = 0
17+
trace(..._params: any[]): void {
18+
}
19+
20+
debug(..._params: any[]): void {
21+
}
22+
23+
info(..._params: any[]): void {
24+
}
25+
26+
warn(..._params: any[]): void {
27+
}
28+
29+
error(..._params: any[]): void {
30+
}
31+
32+
fatal(..._params: any[]): void {
33+
}
34+
35+
}
36+
1437
/**
1538
* Database Management
1639
*/
@@ -39,16 +62,15 @@ export class DatabaseAgent {
3962
const { database } = mongodb_uri.parse(Config.DB_URI)
4063
const accessor = new MongoAccessor(database, Config.DB_URI)
4164

42-
const accessorLogger: any = log4js.getLogger('accessor')
43-
accessorLogger.level = 'warning'
44-
accessor.setLogger(accessorLogger as LoggerInterface)
65+
const accessorLogger = new AccessorLogger()
66+
accessor.setLogger(accessorLogger)
4567
accessor
4668
.init()
4769
.then(async () => {
4870
logger.info('db connected')
4971
})
5072
.catch((error) => {
51-
accessorLogger.error(error)
73+
logger.error(error)
5274
setTimeout(() => process.exit(101), 0)
5375
})
5476

runtimes/nodejs/src/handler/typings.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ import { logger } from '../support/logger'
1212
import { IRequest } from '../support/types'
1313
import { parseToken } from '../support/token'
1414
import { FunctionCache } from '../support/engine'
15+
import Config from '../config'
16+
import * as fs from 'fs'
1517

1618
const nodeModulesRoot = path.resolve(__dirname, '../../node_modules')
1719

1820
/**
1921
* Gets declaration files of a dependency package
2022
*/
2123
export async function handlePackageTypings(req: IRequest, res: Response) {
22-
const requestId = req['requestId']
2324

2425
// verify the debug token
2526
const token = req.get('x-laf-develop-token')
@@ -77,9 +78,22 @@ export async function handlePackageTypings(req: IRequest, res: Response) {
7778
})
7879
}
7980

81+
// get custom dependency types
82+
const customDependencyPath = `${Config.CUSTOM_DEPENDENCY_BASE_PATH}/node_modules/`
83+
if (fs.existsSync(`${customDependencyPath}/${packageName}`)) {
84+
getThreePartyPackageTypings(req, res, customDependencyPath, packageName)
85+
} else {
86+
getThreePartyPackageTypings(req, res, nodeModulesRoot, packageName)
87+
}
88+
}
89+
90+
91+
92+
async function getThreePartyPackageTypings(req: IRequest, res: Response, basePath: string, packageName: string) {
93+
const requestId = req['requestId']
8094
try {
8195
// Gets other three-party package types
82-
const pkd = new PackageDeclaration(packageName, nodeModulesRoot)
96+
const pkd = new PackageDeclaration(packageName, basePath)
8397
await pkd.load()
8498
return res.send({
8599
code: 0,
@@ -92,4 +106,4 @@ export async function handlePackageTypings(req: IRequest, res: Response) {
92106
error: error.toString(),
93107
})
94108
}
95-
}
109+
}

runtimes/nodejs/src/support/engine/module.ts

+23-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ import { FunctionCache, FunctionModuleGlobalContext } from '.'
33
import Config from '../../config'
44
import { Console } from '.'
55
import * as vm from 'vm'
6+
import { createRequire } from 'node:module'
7+
8+
const CUSTOM_DEPENDENCY_NODE_MODULES_PATH = `${Config.CUSTOM_DEPENDENCY_BASE_PATH}/node_modules/`
69

710
export class FunctionModule {
811
protected static cache: Map<string, any> = new Map()
912

13+
private static customRequire = createRequire(
14+
CUSTOM_DEPENDENCY_NODE_MODULES_PATH,
15+
)
16+
1017
static get(functionName: string): any {
1118
const moduleName = `@/${functionName}`
1219
return this.require(moduleName, [])
@@ -40,7 +47,13 @@ export class FunctionModule {
4047
}
4148
return mod
4249
}
43-
return require(name)
50+
51+
// load custom dependency from custom dependency path first
52+
try {
53+
return FunctionModule.customRequire(name)
54+
} catch (e) {
55+
return require(name)
56+
}
4457
}
4558

4659
/**
@@ -62,9 +75,11 @@ export class FunctionModule {
6275
filename: `FunctionModule.${functionName}`,
6376
displayErrors: true,
6477
contextCodeGeneration: {
65-
strings: false,
78+
strings: true,
79+
wasm: true,
6680
},
6781
} as any
82+
6883
const script = this.createScript(wrapped, {})
6984
return script.runInNewContext(sandbox, options)
7085
}
@@ -94,13 +109,17 @@ export class FunctionModule {
94109
): vm.Script {
95110
const _options = {
96111
...options,
97-
98112
importModuleDynamically: async (
99113
specifier: string,
100114
_: vm.Script,
101115
_importAssertions: any,
102116
) => {
103-
return await import(specifier)
117+
try {
118+
const resolvedPath = FunctionModule.customRequire.resolve(specifier)
119+
return await import(resolvedPath)
120+
} catch (e) {
121+
return await import(specifier)
122+
}
104123
},
105124
} as any
106125

runtimes/nodejs/start.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/sh
22

33
# source .env
4-
echo "****** start service: node $FLAGS --experimental-fetch ./dist/index.js *******"
5-
exec node $FLAGS ./dist/index.js
4+
echo "****** start service: node $FLAGS --experimental-vm-modules --experimental-fetch ./dist/index.js *******"
5+
exec node $FLAGS --experimental-vm-modules --experimental-fetch ./dist/index.js

server/README.md

+6-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
- app storage management
1111
- app log management
1212
- app instance management
13+
- app billing management
14+
- app domain management
15+
- app certificate management
16+
- app metrics management
1317

1418
# Development
1519

@@ -21,8 +25,6 @@
2125
- [Telepresence](https://www.telepresence.io) for local development
2226
- [MongoDb](https://docs.mongodb.com) basic use
2327
- [MinIO](https://min.io) object storage
24-
- [APISIX](https://apisix.apache.org) gateway
25-
- [nestjs-i18n](https://nestjs-i18n.com/) i18n
2628

2729
## Prerequisites
2830

@@ -44,15 +46,11 @@ telepresence connect -n laf-system
4446
telepresence intercept laf-server -p 3000:3000 -e $(pwd)/.env
4547

4648
npm install
47-
npm run watch
49+
npm run dev
4850
```
4951

5052
> Clean up
5153
5254
```bash
5355
telepresence leave laf-server
54-
```
55-
56-
## Troubleshooting
57-
58-
- `telepresence helm install` failed for `arm64 / Apple Chip` cluster, please upgrade your telepresence to `v2.11.1` or later.
56+
```

0 commit comments

Comments
 (0)