@symbiote-native/angular 0.2.0 → 0.3.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/babel-linker.cjs +8 -0
- package/bin/symbiote-angular-dev.cjs +51 -0
- package/metro-config.cjs +49 -0
- package/metro-css-parser.cjs +4 -1
- package/package.json +16 -6
- package/tsconfig.angular.base.json +23 -0
package/babel-linker.cjs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Normalizes @angular/compiler-cli/linker/babel's export shape — depending on how a
|
|
2
|
+
// consumer's Metro/Babel setup loads it, the plugin lands as either the plugin function itself
|
|
3
|
+
// or a `{ default: plugin }` wrapper — so a consumer's babel.config.js just requires this
|
|
4
|
+
// instead of re-deriving the `.default ?? angularLinker` fallback itself. See the
|
|
5
|
+
// angular-adapter-build skill for the full ngc → linker AOT pipeline this plugs into.
|
|
6
|
+
const angularLinkerModule = require('@angular/compiler-cli/linker/babel');
|
|
7
|
+
|
|
8
|
+
module.exports = angularLinkerModule.default ?? angularLinkerModule;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Cross-platform replacement for the old per-app dev-with-watch.sh: Angular needs a pre-Metro
|
|
3
|
+
// AOT compile (ngc), kept in sync via `ngc --watch` while developing (see the angular-adapter
|
|
4
|
+
// skill, §4). Metro itself must stay the FOREGROUND process — it reads raw keypresses
|
|
5
|
+
// (r/j/d/...) straight off stdin, and any wrapper that pipes stdin through itself
|
|
6
|
+
// (concurrently, npm-run-all, ...) breaks that raw-mode read. So ngc runs as a plain background
|
|
7
|
+
// child process, never a stdin-owning process manager. `shell: true` resolves `ngc`/
|
|
8
|
+
// `react-native` off PATH exactly like the bash script did — npm/pnpm/yarn already prepend
|
|
9
|
+
// every `node_modules/.bin` up the tree to PATH for any script invocation, this one included.
|
|
10
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
11
|
+
|
|
12
|
+
const TSCONFIG = 'tsconfig.angular.json';
|
|
13
|
+
const metroArgs = process.argv.slice(2);
|
|
14
|
+
|
|
15
|
+
// Without watchman, Metro falls back to chokidar's native fs.watch, which opens one OS file
|
|
16
|
+
// handle per watched directory. This project's watchFolders spans the whole monorepo, so that
|
|
17
|
+
// reliably blows past macOS's per-process fd limit (EMFILE) — doubly likely here since ngc
|
|
18
|
+
// --watch adds a second watcher on top of Metro's own. Warn instead of letting everyone
|
|
19
|
+
// individually debug a native stack trace down to this one missing binary.
|
|
20
|
+
const watchmanCheck = spawnSync('watchman', ['--version'], { stdio: 'ignore', shell: true });
|
|
21
|
+
if (watchmanCheck.status !== 0) {
|
|
22
|
+
console.warn(
|
|
23
|
+
'[symbiote-angular-dev] watchman not found on PATH. Metro will fall back to watching files ' +
|
|
24
|
+
'itself, which commonly crashes with "EMFILE: too many open files" on a repo this size. ' +
|
|
25
|
+
'Install it: https://facebook.github.io/watchman/docs/install (macOS: brew install watchman).',
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const initialBuild = spawnSync('ngc', ['-p', TSCONFIG], { stdio: 'inherit', shell: true });
|
|
30
|
+
if (initialBuild.status !== 0) {
|
|
31
|
+
process.exit(initialBuild.status ?? 1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const ngcWatch = spawn('ngc', ['-p', TSCONFIG, '--watch'], { stdio: 'inherit', shell: true });
|
|
35
|
+
const metro = spawn('react-native', ['start', ...metroArgs], { stdio: 'inherit', shell: true });
|
|
36
|
+
|
|
37
|
+
function stopNgcWatch() {
|
|
38
|
+
ngcWatch.kill();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
metro.on('exit', (code) => {
|
|
42
|
+
stopNgcWatch();
|
|
43
|
+
process.exit(code ?? 0);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
47
|
+
process.on(signal, () => {
|
|
48
|
+
stopNgcWatch();
|
|
49
|
+
metro.kill(signal);
|
|
50
|
+
});
|
|
51
|
+
}
|
package/metro-config.cjs
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Angular's AOT pipeline needs ONE Metro-side accommodation beyond the plain css-parser
|
|
2
|
+
// transformer: ngc mirrors this app's whole source tree into its own outDir (see
|
|
3
|
+
// tsconfig.angular.base.json's `outDir` convention, "build/angular" by default) but only ever
|
|
4
|
+
// compiles .ts — a relative style import (`import './App.css'`) survives untouched in the
|
|
5
|
+
// compiled .js, still pointing at the ORIGINAL source location, which ngc never copies there.
|
|
6
|
+
// Metro resolves that relative specifier against the COMPILED file's own location
|
|
7
|
+
// (<outDir>/...), so without this it 404s on a file that was never created there. This redirects
|
|
8
|
+
// such an import back to the real source file instead of copying it — a copy would need its own
|
|
9
|
+
// re-copy on every CSS edit during `ngc --watch` (which only re-runs on .ts changes), while this
|
|
10
|
+
// redirect lets Metro's own watchFolders pick up a source-file CSS edit for free. Applies
|
|
11
|
+
// identically to a release `react-native bundle`, which resolves through this same config.
|
|
12
|
+
//
|
|
13
|
+
// watchFolders/extraNodeModules are intentionally NOT included here — those are monorepo-only
|
|
14
|
+
// pnpm-workspace concerns (deduping a single react/@angular/core copy across packages), not
|
|
15
|
+
// relevant to an external app installing @symbiote-native/angular from npm; a consumer keeps
|
|
16
|
+
// those local to their own metro.config.js if it needs them at all. See the
|
|
17
|
+
// symbiote-sfc-style-compiler and angular-adapter-build skills.
|
|
18
|
+
const fs = require('node:fs');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
|
|
21
|
+
function withSymbioteAngularMetroConfig(defaultConfig, projectRoot, { outDir = 'build/angular' } = {}) {
|
|
22
|
+
const buildRoot = path.join(projectRoot, ...outDir.split('/'));
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
resolver: {
|
|
26
|
+
// Teach Metro that a style file is a source file (the transformer above turns it into a
|
|
27
|
+
// module). scss/sass/less/styl are optional preprocessor sources — see
|
|
28
|
+
// core/css-parser/src/preprocessors.ts.
|
|
29
|
+
sourceExts: [...defaultConfig.resolver.sourceExts, 'css', 'scss', 'sass', 'less', 'styl'],
|
|
30
|
+
resolveRequest: (context, moduleName, platform) => {
|
|
31
|
+
const isRelativeStyleImport =
|
|
32
|
+
/^\.\.?\//.test(moduleName) && /\.(css|scss|sass|less|styl)$/.test(moduleName);
|
|
33
|
+
if (isRelativeStyleImport) {
|
|
34
|
+
const originDir = path.dirname(context.originModulePath);
|
|
35
|
+
if (originDir === buildRoot || originDir.startsWith(buildRoot + path.sep)) {
|
|
36
|
+
const sourceDir = path.join(projectRoot, path.relative(buildRoot, originDir));
|
|
37
|
+
const sourceFile = path.resolve(sourceDir, moduleName);
|
|
38
|
+
if (fs.existsSync(sourceFile)) {
|
|
39
|
+
return { type: 'sourceFile', filePath: sourceFile };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return context.resolveRequest(context, moduleName, platform);
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { withSymbioteAngularMetroConfig };
|
package/metro-css-parser.cjs
CHANGED
|
@@ -8,4 +8,7 @@
|
|
|
8
8
|
// the way a flat classic node_modules would). .cjs, not .js: this package is "type": "module",
|
|
9
9
|
// and Metro's babelTransformerPath loading expects a require()-able module. See the
|
|
10
10
|
// symbiote-sfc-style-compiler skill.
|
|
11
|
-
|
|
11
|
+
// createCssMetroTransformer is a factory, not a ready transformer — Metro's
|
|
12
|
+
// babelTransformerPath needs the actual {transform, getCacheKey} object it returns,
|
|
13
|
+
// not the css-parser package barrel.
|
|
14
|
+
module.exports = require('@symbiote-native/css-parser').createCssMetroTransformer();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "SymbioteNative's Angular adapter — a Renderer2/RendererFactory2 with DOM-less bootstrap driving real native iOS/Android views through the same engine as the other adapters.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,20 +27,31 @@
|
|
|
27
27
|
"react-native": "./build/angular/bootstrap.js",
|
|
28
28
|
"default": "./src/bootstrap.ts"
|
|
29
29
|
},
|
|
30
|
-
"./metro-css-parser": "./metro-css-parser.cjs"
|
|
30
|
+
"./metro-css-parser": "./metro-css-parser.cjs",
|
|
31
|
+
"./metro-config": "./metro-config.cjs",
|
|
32
|
+
"./babel-linker": "./babel-linker.cjs",
|
|
33
|
+
"./tsconfig.angular.base.json": "./tsconfig.angular.base.json"
|
|
31
34
|
},
|
|
32
35
|
"files": [
|
|
33
36
|
"src",
|
|
34
37
|
"build",
|
|
35
|
-
"
|
|
38
|
+
"bin",
|
|
39
|
+
"metro-css-parser.cjs",
|
|
40
|
+
"metro-config.cjs",
|
|
41
|
+
"babel-linker.cjs",
|
|
42
|
+
"tsconfig.angular.base.json"
|
|
36
43
|
],
|
|
44
|
+
"bin": {
|
|
45
|
+
"symbiote-angular-dev": "./bin/symbiote-angular-dev.cjs"
|
|
46
|
+
},
|
|
37
47
|
"publishConfig": {
|
|
38
48
|
"access": "public"
|
|
39
49
|
},
|
|
40
50
|
"dependencies": {
|
|
51
|
+
"@angular/compiler-cli": "^22",
|
|
52
|
+
"@symbiote-native/components": "0.2.0",
|
|
41
53
|
"@symbiote-native/engine": "0.1.1",
|
|
42
|
-
"@symbiote-native/css-parser": "0.
|
|
43
|
-
"@symbiote-native/components": "0.2.0"
|
|
54
|
+
"@symbiote-native/css-parser": "0.2.0"
|
|
44
55
|
},
|
|
45
56
|
"peerDependencies": {
|
|
46
57
|
"@angular/core": ">=20",
|
|
@@ -48,7 +59,6 @@
|
|
|
48
59
|
},
|
|
49
60
|
"devDependencies": {
|
|
50
61
|
"@angular/compiler": "^22",
|
|
51
|
-
"@angular/compiler-cli": "^22",
|
|
52
62
|
"@angular/core": "^22",
|
|
53
63
|
"@types/node": "^26.0.0",
|
|
54
64
|
"typescript": "~6.0.0",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"noEmit": false,
|
|
9
|
+
"allowImportingTsExtensions": false,
|
|
10
|
+
"declaration": false,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"lib": ["ES2022", "DOM"],
|
|
13
|
+
"types": ["node"],
|
|
14
|
+
"ignoreDeprecations": "6.0",
|
|
15
|
+
"esModuleInterop": true,
|
|
16
|
+
"allowSyntheticDefaultImports": true,
|
|
17
|
+
"resolveJsonModule": true
|
|
18
|
+
},
|
|
19
|
+
"angularCompilerOptions": {
|
|
20
|
+
"compilationMode": "partial",
|
|
21
|
+
"strictTemplates": true
|
|
22
|
+
}
|
|
23
|
+
}
|