proteum 2.5.7 → 2.5.8
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/cli/commands/dev.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { spawn, ChildProcess } from 'child_process';
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
|
-
import type
|
|
9
|
+
import { realpathSync, watch, type FSWatcher } from 'fs';
|
|
10
10
|
import prompts from 'prompts';
|
|
11
11
|
import { UsageError } from 'clipanion';
|
|
12
12
|
|
|
@@ -677,6 +677,16 @@ function normalizeWatchPath(watchPath: string) {
|
|
|
677
677
|
return path.resolve(watchPath).replace(/\\/g, '/').replace(/\/$/, '');
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
+
const resolveWatchPathAliases = (watchPath: string) => {
|
|
681
|
+
const aliases = new Set([normalizeWatchPath(watchPath)]);
|
|
682
|
+
|
|
683
|
+
try {
|
|
684
|
+
aliases.add(normalizeWatchPath(realpathSync(watchPath)));
|
|
685
|
+
} catch {}
|
|
686
|
+
|
|
687
|
+
return [...aliases];
|
|
688
|
+
};
|
|
689
|
+
|
|
680
690
|
type TIndexedSourceWatchEvent = 'change' | 'rename';
|
|
681
691
|
type TIndexedSourceWatchCompilerName = 'server' | 'client';
|
|
682
692
|
type TIndexedSourceWatchInvalidateTarget = 'all' | TIndexedSourceWatchCompilerName;
|
|
@@ -692,14 +702,7 @@ type TMultiWatchingLike = TDevWatching & { watchings?: TNamedWatching[] };
|
|
|
692
702
|
|
|
693
703
|
const resolveIndexedSourceWatchRules = (): TIndexedSourceWatchRule[] => {
|
|
694
704
|
const transpileWatchRoots = app.transpileModuleDirectories
|
|
695
|
-
.
|
|
696
|
-
try {
|
|
697
|
-
return fs.realpathSync(rootPath);
|
|
698
|
-
} catch {
|
|
699
|
-
return rootPath;
|
|
700
|
-
}
|
|
701
|
-
})
|
|
702
|
-
.map(normalizeWatchPath)
|
|
705
|
+
.flatMap((rootPath) => resolveWatchPathAliases(rootPath))
|
|
703
706
|
.filter((rootPath, index, list) => list.indexOf(rootPath) === index);
|
|
704
707
|
|
|
705
708
|
return [
|
|
@@ -723,7 +726,7 @@ const resolveIndexedSourceWatchRules = (): TIndexedSourceWatchRule[] => {
|
|
|
723
726
|
rootPath,
|
|
724
727
|
relativePathPattern: transpileSourceWatchPattern,
|
|
725
728
|
eventTypes: ['change', 'rename'],
|
|
726
|
-
invalidateTargets: ['
|
|
729
|
+
invalidateTargets: ['all'],
|
|
727
730
|
}),
|
|
728
731
|
),
|
|
729
732
|
];
|
|
@@ -848,7 +851,7 @@ const createIndexedSourceWatching = ({
|
|
|
848
851
|
if (!fs.existsSync(rootPath)) continue;
|
|
849
852
|
|
|
850
853
|
watchers.push(
|
|
851
|
-
|
|
854
|
+
watch(rootPath, { recursive: true }, (eventType, filename) => {
|
|
852
855
|
const relativePath = typeof filename === 'string' ? filename.replace(/\\/g, '/').replace(/^\.\//, '') : '';
|
|
853
856
|
const normalizedEventType: TIndexedSourceWatchEvent = eventType === 'change' ? 'change' : 'rename';
|
|
854
857
|
|
|
@@ -44,10 +44,12 @@ export default function createCommonConfig(
|
|
|
44
44
|
outputTarget: TCompileOutputTarget = mode === 'dev' ? 'dev' : 'bin',
|
|
45
45
|
): Configuration {
|
|
46
46
|
const dev = mode === 'dev';
|
|
47
|
-
const enableFilesystemCache = dev ? cli.args.cache !== false : cli.args.cache === true;
|
|
48
47
|
const transpileModuleDirectories = app.transpileModuleDirectories;
|
|
48
|
+
const hasTranspileModuleDirectories = transpileModuleDirectories.length > 0;
|
|
49
|
+
// Persistent cache can restore stale modules from mutable workspace packages even after manual invalidation.
|
|
50
|
+
const enableFilesystemCache = dev ? cli.args.cache !== false && !hasTranspileModuleDirectories : cli.args.cache === true;
|
|
49
51
|
const transpileModuleSnapshot =
|
|
50
|
-
dev &&
|
|
52
|
+
dev && hasTranspileModuleDirectories
|
|
51
53
|
? {
|
|
52
54
|
// Transpiled local packages can resolve through node_modules symlinks,
|
|
53
55
|
// but they still need live invalidation like mutable app sources in dev.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proteum",
|
|
3
3
|
"description": "LLM-first Opinionated Typescript Framework for web applications.",
|
|
4
|
-
"version": "2.5.
|
|
4
|
+
"version": "2.5.8",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/proteum.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -103,6 +103,21 @@ const waitForAssetContaining = async (appRoot, extension, marker, timeoutMs = 60
|
|
|
103
103
|
throw new Error(`Timed out waiting for ${extension} asset containing ${marker}.`);
|
|
104
104
|
};
|
|
105
105
|
|
|
106
|
+
const waitForBodyContaining = async (port, urlPath, marker, timeoutMs = 60000) => {
|
|
107
|
+
const deadline = Date.now() + timeoutMs;
|
|
108
|
+
|
|
109
|
+
while (Date.now() < deadline) {
|
|
110
|
+
try {
|
|
111
|
+
const { body } = await request(port, urlPath, { Accept: 'text/html' });
|
|
112
|
+
if (body.includes(marker)) return body;
|
|
113
|
+
} catch {}
|
|
114
|
+
|
|
115
|
+
await sleep(250);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw new Error(`Timed out waiting for ${urlPath} body containing ${marker}.`);
|
|
119
|
+
};
|
|
120
|
+
|
|
106
121
|
const waitForSessionReady = async (sessionFile, child, getOutput, timeoutMs = 90000) => {
|
|
107
122
|
const deadline = Date.now() + timeoutMs;
|
|
108
123
|
|
|
@@ -199,8 +214,13 @@ const createSharedStyleSource = (marker) => `.shared-style-marker {
|
|
|
199
214
|
`;
|
|
200
215
|
|
|
201
216
|
const createFixture = (root, port, options = {}) => {
|
|
202
|
-
const
|
|
203
|
-
const
|
|
217
|
+
const monorepoRootInstall = options.monorepoRootInstall === true;
|
|
218
|
+
const appRoot = monorepoRootInstall ? path.join(root, 'apps', 'app') : path.join(root, 'app');
|
|
219
|
+
const sharedRoot = monorepoRootInstall ? path.join(root, 'packages', 'shared') : path.join(root, 'shared');
|
|
220
|
+
const sharedDependency = monorepoRootInstall ? 'file:../../packages/shared' : 'file:../shared';
|
|
221
|
+
const sharedInstallRoot = monorepoRootInstall
|
|
222
|
+
? path.join(root, 'node_modules', '@test', 'shared')
|
|
223
|
+
: path.join(appRoot, 'node_modules', '@test', 'shared');
|
|
204
224
|
const cacheConfigSource = options.routerCache ? ` cache: ${options.routerCache},\n` : '';
|
|
205
225
|
|
|
206
226
|
fs.mkdirSync(path.join(appRoot, 'public'), { recursive: true });
|
|
@@ -217,7 +237,7 @@ const createFixture = (root, port, options = {}) => {
|
|
|
217
237
|
private: true,
|
|
218
238
|
version: '0.0.0',
|
|
219
239
|
dependencies: {
|
|
220
|
-
'@test/shared':
|
|
240
|
+
'@test/shared': sharedDependency,
|
|
221
241
|
proteum: `file:${coreRoot}`,
|
|
222
242
|
},
|
|
223
243
|
},
|
|
@@ -474,7 +494,7 @@ export default definePageRoute({
|
|
|
474
494
|
writeFile(path.join(sharedRoot, 'styles.css'), createSharedStyleSource('STYLE_MARKER_INITIAL'));
|
|
475
495
|
|
|
476
496
|
createSymlink(coreRoot, path.join(appRoot, 'node_modules', 'proteum'));
|
|
477
|
-
createSymlink(sharedRoot,
|
|
497
|
+
createSymlink(sharedRoot, sharedInstallRoot);
|
|
478
498
|
|
|
479
499
|
return {
|
|
480
500
|
appRoot,
|
|
@@ -500,11 +520,14 @@ const stopDevServer = async (child) => {
|
|
|
500
520
|
});
|
|
501
521
|
};
|
|
502
522
|
|
|
503
|
-
const startDevServer = (appRoot, port, sessionFile) => {
|
|
523
|
+
const startDevServer = (appRoot, port, sessionFile, options = {}) => {
|
|
504
524
|
let output = '';
|
|
525
|
+
const args = [cliBin, 'dev', '--cwd', appRoot, '--port', String(port), '--session-file', sessionFile];
|
|
526
|
+
if (options.noCache !== false) args.push('--no-cache');
|
|
527
|
+
args.push('--verbose');
|
|
505
528
|
const child = spawn(
|
|
506
529
|
process.execPath,
|
|
507
|
-
|
|
530
|
+
args,
|
|
508
531
|
{
|
|
509
532
|
cwd: appRoot,
|
|
510
533
|
env: {
|
|
@@ -577,6 +600,41 @@ test('proteum dev invalidates client assets and reloads for transpiled package s
|
|
|
577
600
|
}
|
|
578
601
|
});
|
|
579
602
|
|
|
603
|
+
test(
|
|
604
|
+
'proteum dev invalidates SSR and client assets for monorepo-root transpiled package installs',
|
|
605
|
+
{ timeout: 180000 },
|
|
606
|
+
async () => {
|
|
607
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'proteum-monorepo-transpile-watch-'));
|
|
608
|
+
const port = await resolvePortPair();
|
|
609
|
+
const { appRoot, sharedRoot } = createFixture(root, port, { monorepoRootInstall: true });
|
|
610
|
+
const sessionFile = path.join(appRoot, 'var', 'run', 'proteum', 'dev', 'monorepo-transpile-watch-test.json');
|
|
611
|
+
const { child, getOutput } = startDevServer(appRoot, port, sessionFile, { noCache: false });
|
|
612
|
+
|
|
613
|
+
try {
|
|
614
|
+
await waitForSessionReady(sessionFile, child, getOutput);
|
|
615
|
+
await waitForBodyContaining(port, '/', 'SCRIPT_MARKER_INITIAL').catch((error) => {
|
|
616
|
+
throw new Error(`${error.message}\n${getOutput()}`);
|
|
617
|
+
});
|
|
618
|
+
await waitForAssetContaining(appRoot, '.js', 'SCRIPT_MARKER_INITIAL').catch((error) => {
|
|
619
|
+
throw new Error(`${error.message}\n${getOutput()}`);
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
const reloadStream = await connectToReloadStream(port + 1);
|
|
623
|
+
writeFile(path.join(sharedRoot, 'index.tsx'), createSharedIndexSource('SCRIPT_MARKER_MONOREPO_UPDATED'));
|
|
624
|
+
|
|
625
|
+
await waitForAssetContaining(appRoot, '.js', 'SCRIPT_MARKER_MONOREPO_UPDATED');
|
|
626
|
+
await waitForBodyContaining(port, '/', 'SCRIPT_MARKER_MONOREPO_UPDATED');
|
|
627
|
+
const reloadEvent = await reloadStream.waitForReload();
|
|
628
|
+
reloadStream.close();
|
|
629
|
+
|
|
630
|
+
assert.equal(reloadEvent.type, 'reload');
|
|
631
|
+
} finally {
|
|
632
|
+
await stopDevServer(child);
|
|
633
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
);
|
|
637
|
+
|
|
580
638
|
test('proteum dev applies router HTTP cache config to HTML and public assets', { timeout: 180000 }, async () => {
|
|
581
639
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'proteum-router-cache-'));
|
|
582
640
|
const port = await resolvePortPair();
|