@jsenv/core 26.0.0 → 26.0.1
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/package.json +1 -1
- package/readme.md +2 -7
- package/src/internal/compile_server/compile_file.js +2 -0
- package/src/internal/compile_server/compiled_file_service.js +1 -0
- package/src/internal/compile_server/jsenv_directory/jsenv_directory.js +17 -8
- package/src/internal/compile_server/jsenv_directory/update_compile_cache.js +90 -109
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -291,11 +291,6 @@ _jsenv.config.mjs_ is meant to share configuration, other files will simply impo
|
|
|
291
291
|
import { buildProject } from '@jsenv/core'
|
|
292
292
|
|
|
293
293
|
+ import { projectDirectoryUrl } from "./jsenv.config.mjs"
|
|
294
|
-
|
|
295
|
-
await buildProject({
|
|
296
|
-
- projectDirectoryUrl: new URL('./', import.meta.url)
|
|
297
|
-
+ projectDirectoryUrl
|
|
298
|
-
})
|
|
299
294
|
```
|
|
300
295
|
|
|
301
296
|
> We recommend to use ".mjs" extension when a file is written for Node.js but you can name the file as you want, "jsenv.config.js" is fine too.
|
|
@@ -324,10 +319,10 @@ Jsenv relies on **standard web features**. Each standard listed below is potenti
|
|
|
324
319
|
|
|
325
320
|
- `<script type="module">`
|
|
326
321
|
- `<script type="importmap">`
|
|
327
|
-
- top level await
|
|
328
|
-
- import.meta.url
|
|
329
322
|
- dynamic imports
|
|
323
|
+
- import.meta.url
|
|
330
324
|
- import assertions
|
|
325
|
+
- top level await
|
|
331
326
|
|
|
332
327
|
## When to use it?
|
|
333
328
|
|
|
@@ -14,6 +14,7 @@ export const compileFile = async ({
|
|
|
14
14
|
logger,
|
|
15
15
|
|
|
16
16
|
projectDirectoryUrl,
|
|
17
|
+
jsenvDirectory,
|
|
17
18
|
jsenvRemoteDirectory,
|
|
18
19
|
originalFileUrl,
|
|
19
20
|
compiledFileUrl,
|
|
@@ -103,6 +104,7 @@ export const compileFile = async ({
|
|
|
103
104
|
// when serving sourcemap files
|
|
104
105
|
await updateCompileCache({
|
|
105
106
|
logger,
|
|
107
|
+
jsenvDirectory,
|
|
106
108
|
meta,
|
|
107
109
|
compileResult,
|
|
108
110
|
compileResultStatus,
|
|
@@ -38,6 +38,7 @@ export const setupJsenvDirectory = async ({
|
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
const compiledFileWriteSignal = { onwrite: () => {} }
|
|
41
42
|
if (compileServerCanWriteOnFilesystem) {
|
|
42
43
|
if (jsenvDirectoryClean) {
|
|
43
44
|
await ensureEmptyDirectory(jsenvDirectoryUrl)
|
|
@@ -46,9 +47,15 @@ export const setupJsenvDirectory = async ({
|
|
|
46
47
|
logger,
|
|
47
48
|
jsenvDirectoryUrl,
|
|
48
49
|
jsenvDirectoryMetaFileUrl,
|
|
49
|
-
writeMetaFile,
|
|
50
50
|
jsenvDirectoryMeta,
|
|
51
51
|
})
|
|
52
|
+
// We want ".jsenv" directory to appear on the filesystem only
|
|
53
|
+
// if there is a compiled file inside (and not immediatly when compile server starts)
|
|
54
|
+
// To do this we wait for a file to be written to write "__jsenv_meta__.json" file
|
|
55
|
+
compiledFileWriteSignal.onwrite = async () => {
|
|
56
|
+
compiledFileWriteSignal.onwrite = () => {}
|
|
57
|
+
await writeMetaFile()
|
|
58
|
+
}
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
/*
|
|
@@ -88,7 +95,7 @@ export const setupJsenvDirectory = async ({
|
|
|
88
95
|
}
|
|
89
96
|
return existingCompileId
|
|
90
97
|
}
|
|
91
|
-
const compileIdBase = generateCompileId({ compileProfile })
|
|
98
|
+
const compileIdBase = generateCompileId({ compileProfile, runtime })
|
|
92
99
|
let compileId = compileIdBase
|
|
93
100
|
let integer = 1
|
|
94
101
|
while (existingCompileIds.includes(compileId)) {
|
|
@@ -106,13 +113,20 @@ export const setupJsenvDirectory = async ({
|
|
|
106
113
|
return {
|
|
107
114
|
compileDirectories,
|
|
108
115
|
getOrCreateCompileId,
|
|
116
|
+
compiledFileWriteSignal,
|
|
109
117
|
}
|
|
110
118
|
}
|
|
111
119
|
|
|
112
|
-
const generateCompileId = ({ compileProfile }) => {
|
|
120
|
+
const generateCompileId = ({ compileProfile, runtime }) => {
|
|
121
|
+
if (runtime.name === "jsenv_build") {
|
|
122
|
+
return `out_build`
|
|
123
|
+
}
|
|
113
124
|
if (compileProfile.missingFeatures["transform-instrument"]) {
|
|
114
125
|
return `out_instrumented`
|
|
115
126
|
}
|
|
127
|
+
if (compileProfile.moduleOutFormat === "systemjs") {
|
|
128
|
+
return `out_system`
|
|
129
|
+
}
|
|
116
130
|
return `out`
|
|
117
131
|
}
|
|
118
132
|
|
|
@@ -121,7 +135,6 @@ const applyFileSystemEffects = async ({
|
|
|
121
135
|
jsenvDirectoryUrl,
|
|
122
136
|
jsenvDirectoryMetaFileUrl,
|
|
123
137
|
jsenvDirectoryMeta,
|
|
124
|
-
writeMetaFile,
|
|
125
138
|
}) => {
|
|
126
139
|
try {
|
|
127
140
|
const source = await readFile(jsenvDirectoryMetaFileUrl)
|
|
@@ -130,7 +143,6 @@ const applyFileSystemEffects = async ({
|
|
|
130
143
|
`${jsenvDirectoryMetaFileUrl} is empty -> clean ${jsenvDirectoryUrl} directory`,
|
|
131
144
|
)
|
|
132
145
|
await ensureEmptyDirectory(jsenvDirectoryUrl)
|
|
133
|
-
await writeMetaFile()
|
|
134
146
|
return
|
|
135
147
|
}
|
|
136
148
|
const jsenvDirectoryMetaPrevious = JSON.parse(source)
|
|
@@ -144,7 +156,6 @@ const applyFileSystemEffects = async ({
|
|
|
144
156
|
`compile context has changed -> clean ${jsenvDirectoryUrl} directory`,
|
|
145
157
|
)
|
|
146
158
|
await ensureEmptyDirectory(jsenvDirectoryUrl)
|
|
147
|
-
await writeMetaFile()
|
|
148
159
|
return
|
|
149
160
|
}
|
|
150
161
|
// reuse existing compile directories
|
|
@@ -158,7 +169,6 @@ const applyFileSystemEffects = async ({
|
|
|
158
169
|
`${jsenvDirectoryMetaFileUrl} not found -> clean ${jsenvDirectoryUrl} directory`,
|
|
159
170
|
)
|
|
160
171
|
await ensureEmptyDirectory(jsenvDirectoryUrl)
|
|
161
|
-
await writeMetaFile()
|
|
162
172
|
return
|
|
163
173
|
}
|
|
164
174
|
if (e.name === "SyntaxError") {
|
|
@@ -166,7 +176,6 @@ const applyFileSystemEffects = async ({
|
|
|
166
176
|
`${jsenvDirectoryMetaFileUrl} syntax error -> clean ${jsenvDirectoryUrl} directory`,
|
|
167
177
|
)
|
|
168
178
|
await ensureEmptyDirectory(jsenvDirectoryUrl)
|
|
169
|
-
await writeMetaFile()
|
|
170
179
|
return
|
|
171
180
|
}
|
|
172
181
|
throw e
|
|
@@ -10,6 +10,7 @@ import { getMetaJsonFileUrl } from "./compile_asset.js"
|
|
|
10
10
|
|
|
11
11
|
export const updateCompileCache = async ({
|
|
12
12
|
logger,
|
|
13
|
+
jsenvDirectory,
|
|
13
14
|
meta,
|
|
14
15
|
compiledFileUrl,
|
|
15
16
|
compileResult,
|
|
@@ -17,6 +18,9 @@ export const updateCompileCache = async ({
|
|
|
17
18
|
}) => {
|
|
18
19
|
const isNew = compileResultStatus === "created"
|
|
19
20
|
const isUpdated = compileResultStatus === "updated"
|
|
21
|
+
if (!isNew && !isUpdated) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
20
24
|
const {
|
|
21
25
|
compiledSource,
|
|
22
26
|
contentType,
|
|
@@ -26,125 +30,102 @@ export const updateCompileCache = async ({
|
|
|
26
30
|
assetsContent,
|
|
27
31
|
dependencies,
|
|
28
32
|
} = compileResult
|
|
29
|
-
|
|
30
33
|
const promises = []
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
logger.warn(`SOURCE_META_NOT_FOUND: ${sourceNotFoundCount} source file(s) not found.
|
|
34
|
+
// ensure source that does not leads to concrete files are not capable to invalidate the cache
|
|
35
|
+
const sourcesToRemove = sources.filter((sourceFileUrl) => {
|
|
36
|
+
return (
|
|
37
|
+
sourceFileUrl.startsWith("file://") && !testFilePresence(sourceFileUrl)
|
|
38
|
+
)
|
|
39
|
+
})
|
|
40
|
+
const sourceNotFoundCount = sourcesToRemove.length
|
|
41
|
+
if (sourceNotFoundCount > 0) {
|
|
42
|
+
logger.warn(`SOURCE_META_NOT_FOUND: ${sourceNotFoundCount} source file(s) not found.
|
|
41
43
|
--- consequence ---
|
|
42
44
|
cache will be reused even if one of the source file is modified
|
|
43
45
|
--- source files not found ---
|
|
44
46
|
${sourcesToRemove.join(`\n`)}`)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const { writeCompiledSourceFile = true, writeAssetsFile = true } =
|
|
55
|
-
compileResult
|
|
56
|
-
|
|
57
|
-
if (writeCompiledSourceFile) {
|
|
58
|
-
logger.debug(
|
|
59
|
-
`write compiled file at ${urlToFileSystemPath(compiledFileUrl)}`,
|
|
60
|
-
)
|
|
61
|
-
promises.push(
|
|
62
|
-
writeFileContent(compiledFileUrl, compiledSource, {
|
|
63
|
-
fileLikelyNotFound: isNew,
|
|
64
|
-
}).then(() => {
|
|
65
|
-
const mtime = compileResult.compiledMtime
|
|
66
|
-
// when compileResult.compiledMtime do not exists it means
|
|
67
|
-
// the client is not interested in it so
|
|
68
|
-
// -> moment we write the file is not important
|
|
69
|
-
// -> There is no need to update mtime
|
|
70
|
-
if (mtime) {
|
|
71
|
-
utimesSync(
|
|
72
|
-
urlToFileSystemPath(compiledFileUrl),
|
|
73
|
-
new Date(mtime),
|
|
74
|
-
new Date(mtime),
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
}),
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (writeAssetsFile) {
|
|
82
|
-
promises.push(
|
|
83
|
-
...assets.map((assetFileUrl, index) => {
|
|
84
|
-
logger.debug(
|
|
85
|
-
`write compiled file asset at ${urlToFileSystemPath(assetFileUrl)}`,
|
|
86
|
-
)
|
|
87
|
-
return writeFileContent(assetFileUrl, assetsContent[index], {
|
|
88
|
-
fileLikelyNotFound: isNew,
|
|
89
|
-
})
|
|
90
|
-
}),
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const metaJsonFileUrl = getMetaJsonFileUrl(compiledFileUrl)
|
|
96
|
-
|
|
97
|
-
if (isNew || isUpdated) {
|
|
98
|
-
let latestMeta
|
|
99
|
-
|
|
100
|
-
const sourceAndAssetProps = {
|
|
101
|
-
sources: sources.map((source) =>
|
|
102
|
-
urlToRelativeUrl(source, metaJsonFileUrl),
|
|
103
|
-
),
|
|
104
|
-
sourcesEtag: sourcesContent.map((sourceContent) =>
|
|
105
|
-
bufferToEtag(Buffer.from(sourceContent)),
|
|
106
|
-
),
|
|
107
|
-
assets: assets.map((asset) => urlToRelativeUrl(asset, metaJsonFileUrl)),
|
|
108
|
-
assetsEtag: assetsContent.map((assetContent) =>
|
|
109
|
-
bufferToEtag(Buffer.from(assetContent)),
|
|
110
|
-
),
|
|
111
|
-
dependencies: dependencies.filter((dep) => {
|
|
112
|
-
return !dep.startsWith("data:")
|
|
113
|
-
}),
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (isNew) {
|
|
117
|
-
latestMeta = {
|
|
118
|
-
contentType,
|
|
119
|
-
...sourceAndAssetProps,
|
|
120
|
-
createdMs: Number(Date.now()),
|
|
121
|
-
lastModifiedMs: Number(Date.now()),
|
|
122
|
-
}
|
|
123
|
-
} else if (isUpdated) {
|
|
124
|
-
latestMeta = {
|
|
125
|
-
...meta,
|
|
126
|
-
...sourceAndAssetProps,
|
|
127
|
-
lastModifiedMs: Number(Date.now()),
|
|
128
|
-
}
|
|
129
|
-
} else {
|
|
130
|
-
latestMeta = {
|
|
131
|
-
...meta,
|
|
47
|
+
sourcesToRemove.forEach((url) => {
|
|
48
|
+
const sourceIndex = sources.indexOf(url)
|
|
49
|
+
if (sourceIndex) {
|
|
50
|
+
sources.splice(sourceIndex, 1)
|
|
51
|
+
sourcesContent.splice(sourceIndex, 1)
|
|
132
52
|
}
|
|
133
|
-
}
|
|
134
|
-
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
const { writeCompiledSourceFile = true, writeAssetsFile = true } =
|
|
56
|
+
compileResult
|
|
57
|
+
if (writeCompiledSourceFile) {
|
|
135
58
|
logger.debug(
|
|
136
|
-
`write compiled file
|
|
59
|
+
`write compiled file at ${urlToFileSystemPath(compiledFileUrl)}`,
|
|
60
|
+
)
|
|
61
|
+
promises.push(
|
|
62
|
+
writeFileContent(compiledFileUrl, compiledSource, {
|
|
63
|
+
fileLikelyNotFound: isNew,
|
|
64
|
+
}).then(() => {
|
|
65
|
+
const mtime = compileResult.compiledMtime
|
|
66
|
+
// when compileResult.compiledMtime do not exists it means
|
|
67
|
+
// the client is not interested in it so
|
|
68
|
+
// -> moment we write the file is not important
|
|
69
|
+
// -> There is no need to update mtime
|
|
70
|
+
if (mtime) {
|
|
71
|
+
utimesSync(
|
|
72
|
+
urlToFileSystemPath(compiledFileUrl),
|
|
73
|
+
new Date(mtime),
|
|
74
|
+
new Date(mtime),
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}),
|
|
137
78
|
)
|
|
79
|
+
}
|
|
80
|
+
if (writeAssetsFile) {
|
|
138
81
|
promises.push(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
82
|
+
...assets.map((assetFileUrl, index) => {
|
|
83
|
+
logger.debug(
|
|
84
|
+
`write compiled file asset at ${urlToFileSystemPath(assetFileUrl)}`,
|
|
85
|
+
)
|
|
86
|
+
return writeFileContent(assetFileUrl, assetsContent[index], {
|
|
143
87
|
fileLikelyNotFound: isNew,
|
|
144
|
-
}
|
|
145
|
-
),
|
|
88
|
+
})
|
|
89
|
+
}),
|
|
146
90
|
)
|
|
147
91
|
}
|
|
148
|
-
|
|
149
|
-
|
|
92
|
+
const metaJsonFileUrl = getMetaJsonFileUrl(compiledFileUrl)
|
|
93
|
+
let latestMeta
|
|
94
|
+
const sourceAndAssetProps = {
|
|
95
|
+
sources: sources.map((source) => urlToRelativeUrl(source, metaJsonFileUrl)),
|
|
96
|
+
sourcesEtag: sourcesContent.map((sourceContent) =>
|
|
97
|
+
bufferToEtag(Buffer.from(sourceContent)),
|
|
98
|
+
),
|
|
99
|
+
assets: assets.map((asset) => urlToRelativeUrl(asset, metaJsonFileUrl)),
|
|
100
|
+
assetsEtag: assetsContent.map((assetContent) =>
|
|
101
|
+
bufferToEtag(Buffer.from(assetContent)),
|
|
102
|
+
),
|
|
103
|
+
dependencies: dependencies.filter((dep) => {
|
|
104
|
+
return !dep.startsWith("data:")
|
|
105
|
+
}),
|
|
106
|
+
}
|
|
107
|
+
if (isNew) {
|
|
108
|
+
latestMeta = {
|
|
109
|
+
contentType,
|
|
110
|
+
...sourceAndAssetProps,
|
|
111
|
+
createdMs: Number(Date.now()),
|
|
112
|
+
lastModifiedMs: Number(Date.now()),
|
|
113
|
+
}
|
|
114
|
+
} else if (isUpdated) {
|
|
115
|
+
latestMeta = {
|
|
116
|
+
...meta,
|
|
117
|
+
...sourceAndAssetProps,
|
|
118
|
+
lastModifiedMs: Number(Date.now()),
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
logger.debug(
|
|
122
|
+
`write compiled file meta at ${urlToFileSystemPath(metaJsonFileUrl)}`,
|
|
123
|
+
)
|
|
124
|
+
promises.push(
|
|
125
|
+
writeFileContent(metaJsonFileUrl, JSON.stringify(latestMeta, null, " "), {
|
|
126
|
+
fileLikelyNotFound: isNew,
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
promises.push(jsenvDirectory.compiledFileWriteSignal.onwrite())
|
|
130
|
+
await Promise.all(promises)
|
|
150
131
|
}
|