evolit 0.1.2 → 0.1.4
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/README.md +16 -0
- package/package.json +5 -6
- package/src/client-assets.js +74 -16
- package/src/compiler.js +67 -14
- package/src/scaffold.js +2 -3
- package/templates/default/jsconfig.json +1 -6
package/README.md
CHANGED
|
@@ -46,6 +46,22 @@ Generated applications declare `"@/*": ["./*"]` in `jsconfig.json`, so editors a
|
|
|
46
46
|
use the same convention. An explicit `@/*` mapping in `jsconfig.json` or `tsconfig.json` takes
|
|
47
47
|
priority when an application needs a different source root.
|
|
48
48
|
|
|
49
|
+
### Package CSS and static assets
|
|
50
|
+
|
|
51
|
+
Applications can import stylesheets exposed through package `exports` in the same way as local
|
|
52
|
+
stylesheets:
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
import "@scope/design-system/tokens.css";
|
|
56
|
+
import "@scope/design-system/theme.css";
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Evolit resolves package subpaths with ESM `import` conditions, emits exported CSS through the
|
|
60
|
+
route static-asset pipeline, and adds the resulting stylesheet URLs to the rendered document.
|
|
61
|
+
Relative `@import` rules and `url(...)` references inside package CSS are emitted and rewritten
|
|
62
|
+
from their location within `node_modules`. Bare package imports that resolve to JavaScript continue
|
|
63
|
+
to use the shared vendor runtime; CSS and other static assets do not enter vendor chunks.
|
|
64
|
+
|
|
49
65
|
## Commands
|
|
50
66
|
|
|
51
67
|
```sh
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evolit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "A convention-driven application framework for LitSX and web components.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "yarn@4.10.3",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"start": "node ./src/cli.js start",
|
|
43
43
|
"test": "node --test test/*.test.js",
|
|
44
44
|
"test:browser": "playwright test",
|
|
45
|
-
"typecheck": "
|
|
45
|
+
"typecheck": "tsc -p jsconfig.json --noEmit",
|
|
46
46
|
"release:check": "yarn test && yarn typecheck && yarn pack --dry-run"
|
|
47
47
|
},
|
|
48
48
|
"keywords": [
|
|
@@ -59,10 +59,9 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@jridgewell/remapping": "^2.3.5",
|
|
62
|
-
"@litsx/compiler": "1.0.0-next.
|
|
63
|
-
"@litsx/core": "1.0.0-next.
|
|
64
|
-
"@litsx/ssr": "1.0.0-next.
|
|
65
|
-
"@litsx/typescript": "^0.9.0",
|
|
62
|
+
"@litsx/compiler": "1.0.0-next.12",
|
|
63
|
+
"@litsx/core": "1.0.0-next.8",
|
|
64
|
+
"@litsx/ssr": "1.0.0-next.5",
|
|
66
65
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
67
66
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
68
67
|
"lit": "^3.3.3",
|
package/src/client-assets.js
CHANGED
|
@@ -144,11 +144,36 @@ export async function resolvePackageRoot(packageName, options = {}) {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
const pendingResolution = (async () => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
const resolvers = [
|
|
148
|
+
createRequire(path.join(resolveFrom, "package.json")),
|
|
149
|
+
requireFromHere,
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
for (const resolver of resolvers) {
|
|
153
|
+
try {
|
|
154
|
+
const packageJsonPath = resolver.resolve(`${packageName}/package.json`);
|
|
155
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
|
|
156
|
+
if (packageJson?.name === packageName) {
|
|
157
|
+
return { packageRoot: path.dirname(packageJsonPath), packageJson };
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
// Some packages intentionally do not export package.json. Resolve the
|
|
161
|
+
// entrypoint below and walk back to its owning manifest instead.
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let packageEntryPath = null;
|
|
166
|
+
let resolutionError = null;
|
|
167
|
+
for (const resolver of resolvers) {
|
|
168
|
+
try {
|
|
169
|
+
packageEntryPath = resolver.resolve(packageName);
|
|
170
|
+
break;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
resolutionError = error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!packageEntryPath) {
|
|
176
|
+
throw resolutionError ?? new Error(`Unable to resolve package entry for ${packageName}`);
|
|
152
177
|
}
|
|
153
178
|
let currentPath = path.dirname(packageEntryPath);
|
|
154
179
|
|
|
@@ -190,6 +215,14 @@ function pickBrowserExportTarget(target) {
|
|
|
190
215
|
return target;
|
|
191
216
|
}
|
|
192
217
|
|
|
218
|
+
if (Array.isArray(target)) {
|
|
219
|
+
for (const candidate of target) {
|
|
220
|
+
const resolved = pickBrowserExportTarget(candidate);
|
|
221
|
+
if (resolved) return resolved;
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
193
226
|
if (!target || typeof target !== "object") {
|
|
194
227
|
return null;
|
|
195
228
|
}
|
|
@@ -202,6 +235,33 @@ function pickBrowserExportTarget(target) {
|
|
|
202
235
|
?? null;
|
|
203
236
|
}
|
|
204
237
|
|
|
238
|
+
function resolveBrowserPackageExport(exportsField, exportKey) {
|
|
239
|
+
if (typeof exportsField === "string" || Array.isArray(exportsField)) {
|
|
240
|
+
return exportKey === "." ? pickBrowserExportTarget(exportsField) : null;
|
|
241
|
+
}
|
|
242
|
+
if (!exportsField || typeof exportsField !== "object") {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
if (!Object.keys(exportsField).some((key) => key.startsWith("."))) {
|
|
246
|
+
return exportKey === "." ? pickBrowserExportTarget(exportsField) : null;
|
|
247
|
+
}
|
|
248
|
+
if (exportsField[exportKey] != null) {
|
|
249
|
+
return pickBrowserExportTarget(exportsField[exportKey]);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
for (const [pattern, target] of Object.entries(exportsField)) {
|
|
253
|
+
const wildcardIndex = pattern.indexOf("*");
|
|
254
|
+
if (wildcardIndex < 0) continue;
|
|
255
|
+
const prefix = pattern.slice(0, wildcardIndex);
|
|
256
|
+
const suffix = pattern.slice(wildcardIndex + 1);
|
|
257
|
+
if (!exportKey.startsWith(prefix) || !exportKey.endsWith(suffix)) continue;
|
|
258
|
+
const wildcard = exportKey.slice(prefix.length, exportKey.length - suffix.length);
|
|
259
|
+
const resolved = pickBrowserExportTarget(target);
|
|
260
|
+
if (resolved) return resolved.replace("*", wildcard);
|
|
261
|
+
}
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
205
265
|
export async function resolveBrowserSpecifierFilePath(specifier, options = {}) {
|
|
206
266
|
if (!isBareSpecifier(specifier)) {
|
|
207
267
|
return null;
|
|
@@ -222,17 +282,15 @@ export async function resolveBrowserSpecifierFilePath(specifier, options = {}) {
|
|
|
222
282
|
const { packageName, subpath } = parsedSpecifier;
|
|
223
283
|
const { packageRoot, packageJson } = await resolvePackageRoot(packageName, { projectRoot: resolveFrom });
|
|
224
284
|
const exportKey = subpath.length > 0 ? `./${subpath}` : ".";
|
|
225
|
-
const
|
|
226
|
-
const exportTarget =
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
? packageJson.browser
|
|
235
|
-
: packageJson.module ?? packageJson.main ?? null;
|
|
285
|
+
const hasExports = packageJson.exports != null;
|
|
286
|
+
const exportTarget = resolveBrowserPackageExport(packageJson.exports, exportKey);
|
|
287
|
+
const fallbackTarget = hasExports
|
|
288
|
+
? null
|
|
289
|
+
: subpath.length > 0
|
|
290
|
+
? `./${subpath}`
|
|
291
|
+
: typeof packageJson.browser === "string"
|
|
292
|
+
? packageJson.browser
|
|
293
|
+
: packageJson.module ?? packageJson.main ?? null;
|
|
236
294
|
let resolvedTarget = exportTarget ?? fallbackTarget;
|
|
237
295
|
if (resolvedTarget && packageJson.browser && typeof packageJson.browser === "object") {
|
|
238
296
|
const normalizedTarget = resolvedTarget.startsWith("./")
|
package/src/compiler.js
CHANGED
|
@@ -19,6 +19,7 @@ import { ensureDirectory } from "./fs-utils.js";
|
|
|
19
19
|
|
|
20
20
|
const MODULE_SPECIFIER_PATTERN =
|
|
21
21
|
/\b(?:import|export)\s+(?:[^"']*?\s+from\s+)?["']([^"']+)["']|\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
22
|
+
const CSS_DEPENDENCY_PATTERN = /(?:@import\s+(?:url\(\s*)?["']([^"']+)["']\s*\)?|url\(\s*["']?([^"')]+)["']?\s*\))/g;
|
|
22
23
|
const RESOLVABLE_IMPORT_EXTENSIONS = [
|
|
23
24
|
...MODULE_EXTENSIONS,
|
|
24
25
|
...STATIC_ASSET_EXTENSIONS,
|
|
@@ -497,7 +498,8 @@ function createStaticAssetStubSource(relativeAssetPath, mode, target = "server",
|
|
|
497
498
|
}
|
|
498
499
|
|
|
499
500
|
async function resolveImportPath(importerPath, specifier) {
|
|
500
|
-
const
|
|
501
|
+
const cleanSpecifier = String(specifier).split("?")[0].split("#")[0];
|
|
502
|
+
const basePath = path.resolve(path.dirname(importerPath), cleanSpecifier);
|
|
501
503
|
const candidates = [basePath];
|
|
502
504
|
|
|
503
505
|
if (!hasResolvableImportExtension(basePath)) {
|
|
@@ -521,6 +523,29 @@ async function resolveImportPath(importerPath, specifier) {
|
|
|
521
523
|
return null;
|
|
522
524
|
}
|
|
523
525
|
|
|
526
|
+
async function collectStaticAssetGraph(entryPath, collected = new Set()) {
|
|
527
|
+
const normalizedEntryPath = path.resolve(entryPath);
|
|
528
|
+
if (collected.has(normalizedEntryPath) || !isStaticAssetPath(normalizedEntryPath)) {
|
|
529
|
+
return collected;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
collected.add(normalizedEntryPath);
|
|
533
|
+
if (!isStyleAssetPath(normalizedEntryPath)) {
|
|
534
|
+
return collected;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const source = await fs.readFile(normalizedEntryPath, "utf8");
|
|
538
|
+
for (const match of source.matchAll(CSS_DEPENDENCY_PATTERN)) {
|
|
539
|
+
const specifier = match[1] ?? match[2];
|
|
540
|
+
if (!specifier || !isRelativeSpecifier(specifier)) continue;
|
|
541
|
+
const resolvedPath = await resolveImportPath(normalizedEntryPath, specifier);
|
|
542
|
+
if (resolvedPath && isStaticAssetPath(resolvedPath)) {
|
|
543
|
+
await collectStaticAssetGraph(resolvedPath, collected);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return collected;
|
|
547
|
+
}
|
|
548
|
+
|
|
524
549
|
async function loadProjectPathAliases(projectRoot) {
|
|
525
550
|
if (projectPathAliasesCache.has(projectRoot)) return projectPathAliasesCache.get(projectRoot);
|
|
526
551
|
const pending = (async () => {
|
|
@@ -660,12 +685,15 @@ async function resolveProjectPackageImport(projectRoot, importerPath, specifier)
|
|
|
660
685
|
try {
|
|
661
686
|
const packageJson = JSON.parse(await fs.readFile(path.join(packageRoot, "package.json"), "utf8"));
|
|
662
687
|
const exportKey = parsed.subpath ? `./${parsed.subpath}` : ".";
|
|
688
|
+
const hasExports = packageJson.exports != null;
|
|
663
689
|
let target = resolvePackageExports(packageJson.exports, exportKey)
|
|
664
|
-
?? (
|
|
665
|
-
?
|
|
666
|
-
:
|
|
667
|
-
?
|
|
668
|
-
: packageJson.
|
|
690
|
+
?? (hasExports
|
|
691
|
+
? null
|
|
692
|
+
: parsed.subpath
|
|
693
|
+
? `./${parsed.subpath}`
|
|
694
|
+
: typeof packageJson.browser === "string"
|
|
695
|
+
? packageJson.browser
|
|
696
|
+
: packageJson.module ?? packageJson.main);
|
|
669
697
|
if (target && packageJson.browser && typeof packageJson.browser === "object") {
|
|
670
698
|
const normalizedTarget = target.startsWith("./") ? target : `./${target}`;
|
|
671
699
|
const browserTarget = packageJson.browser[normalizedTarget]
|
|
@@ -828,8 +856,19 @@ async function rewriteRelativeSpecifiers({
|
|
|
828
856
|
const aliasedImportPath = isBareSpecifier(specifier)
|
|
829
857
|
? await resolveProjectMappedImport(projectRoot, sourcePath, specifier)
|
|
830
858
|
: null;
|
|
859
|
+
const packageImportPath = isBareSpecifier(specifier) && !aliasedImportPath
|
|
860
|
+
? await resolveProjectPackageImport(projectRoot, sourcePath, specifier)
|
|
861
|
+
: null;
|
|
862
|
+
const packageAssetPath = packageImportPath && isStaticAssetPath(packageImportPath)
|
|
863
|
+
? packageImportPath
|
|
864
|
+
: null;
|
|
831
865
|
|
|
832
|
-
if (
|
|
866
|
+
if (
|
|
867
|
+
target === "client"
|
|
868
|
+
&& isBareSpecifier(specifier)
|
|
869
|
+
&& !aliasedImportPath
|
|
870
|
+
&& !packageAssetPath
|
|
871
|
+
) {
|
|
833
872
|
const sourceMetadata = moduleMetadata.get(sourcePath) ?? {
|
|
834
873
|
moduleImports: new Set(),
|
|
835
874
|
vendorImports: new Set(),
|
|
@@ -841,11 +880,13 @@ async function rewriteRelativeSpecifiers({
|
|
|
841
880
|
continue;
|
|
842
881
|
}
|
|
843
882
|
|
|
844
|
-
if (!isRelativeSpecifier(specifier) && !aliasedImportPath) {
|
|
883
|
+
if (!isRelativeSpecifier(specifier) && !aliasedImportPath && !packageAssetPath) {
|
|
845
884
|
continue;
|
|
846
885
|
}
|
|
847
886
|
|
|
848
|
-
const resolvedImportPath =
|
|
887
|
+
const resolvedImportPath = packageAssetPath
|
|
888
|
+
?? aliasedImportPath
|
|
889
|
+
?? await resolveImportPath(sourcePath, specifier);
|
|
849
890
|
if (!resolvedImportPath) {
|
|
850
891
|
continue;
|
|
851
892
|
}
|
|
@@ -875,7 +916,10 @@ async function rewriteRelativeSpecifiers({
|
|
|
875
916
|
);
|
|
876
917
|
}
|
|
877
918
|
} else if (isStaticAssetPath(resolvedImportPath)) {
|
|
878
|
-
|
|
919
|
+
const staticAssetGraph = await collectStaticAssetGraph(resolvedImportPath);
|
|
920
|
+
for (const staticAssetPath of staticAssetGraph) {
|
|
921
|
+
staticAssetFiles?.add(staticAssetPath);
|
|
922
|
+
}
|
|
879
923
|
const relativeAssetPath = toOutputRelativePath(projectRoot, resolvedImportPath);
|
|
880
924
|
const assetOutputPath = path.join(outputRoot, relativeAssetPath);
|
|
881
925
|
const stubOutputPath = `${assetOutputPath}.mjs`;
|
|
@@ -888,8 +932,14 @@ async function rewriteRelativeSpecifiers({
|
|
|
888
932
|
);
|
|
889
933
|
|
|
890
934
|
if (target === "client") {
|
|
891
|
-
|
|
892
|
-
|
|
935
|
+
for (const staticAssetPath of staticAssetGraph) {
|
|
936
|
+
const staticAssetOutputPath = path.join(
|
|
937
|
+
outputRoot,
|
|
938
|
+
toOutputRelativePath(projectRoot, staticAssetPath),
|
|
939
|
+
);
|
|
940
|
+
await ensureDirectory(path.dirname(staticAssetOutputPath));
|
|
941
|
+
await fs.copyFile(staticAssetPath, staticAssetOutputPath);
|
|
942
|
+
}
|
|
893
943
|
const sourceMetadata = moduleMetadata.get(sourcePath) ?? {
|
|
894
944
|
moduleImports: new Set(),
|
|
895
945
|
vendorImports: new Set(),
|
|
@@ -1239,8 +1289,6 @@ export async function compileModuleGraph(entryPath, options = {}) {
|
|
|
1239
1289
|
}
|
|
1240
1290
|
}
|
|
1241
1291
|
|
|
1242
|
-
const CSS_DEPENDENCY_PATTERN = /(?:@import\s+(?:url\(\s*)?["']([^"']+)["']\s*\)?|url\(\s*["']?([^"')]+)["']?\s*\))/g;
|
|
1243
|
-
|
|
1244
1292
|
function normalizeProjectRelativePath(projectRoot, filePath) {
|
|
1245
1293
|
return toOutputRelativePath(projectRoot, filePath).split(path.sep).join("/");
|
|
1246
1294
|
}
|
|
@@ -1406,8 +1454,13 @@ export async function emitClientStaticAssets(assetPaths, options = {}) {
|
|
|
1406
1454
|
const outputRoot = getTypedOutputRoot(projectRoot, mode, "client");
|
|
1407
1455
|
const emitted = [];
|
|
1408
1456
|
|
|
1457
|
+
const expandedAssetPaths = new Set();
|
|
1409
1458
|
for (const assetPath of new Set(assetPaths ?? [])) {
|
|
1410
1459
|
if (!isStaticAssetPath(assetPath)) continue;
|
|
1460
|
+
await collectStaticAssetGraph(assetPath, expandedAssetPaths);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
for (const assetPath of expandedAssetPaths) {
|
|
1411
1464
|
const relativePath = normalizeProjectRelativePath(projectRoot, assetPath);
|
|
1412
1465
|
const outputPath = path.join(outputRoot, relativePath.split("/").join(path.sep));
|
|
1413
1466
|
await ensureDirectory(path.dirname(outputPath));
|
package/src/scaffold.js
CHANGED
|
@@ -23,14 +23,13 @@ async function writeSitePackageJson(targetDirectory, siteName) {
|
|
|
23
23
|
dev: "evolit dev",
|
|
24
24
|
build: "evolit build",
|
|
25
25
|
start: "evolit start",
|
|
26
|
-
typecheck: "
|
|
26
|
+
typecheck: "tsc -p jsconfig.json --noEmit",
|
|
27
27
|
},
|
|
28
28
|
dependencies: {
|
|
29
|
-
"@litsx/core": "1.0.0-next.
|
|
29
|
+
"@litsx/core": "1.0.0-next.8",
|
|
30
30
|
evolit: frameworkVersion,
|
|
31
31
|
},
|
|
32
32
|
devDependencies: {
|
|
33
|
-
"@litsx/typescript": "^0.9.0",
|
|
34
33
|
"typescript": "^6.0.0",
|
|
35
34
|
},
|
|
36
35
|
};
|