@blotch/angular-lynx-build 0.0.0-stage → 22.2.3
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 +110 -2
- package/builders/angular-build.js +117 -0
- package/builders/application/index.js +165 -0
- package/builders/application/native-cache.js +56 -0
- package/builders/application/schema.js +2 -0
- package/builders/application/schema.json +229 -0
- package/builders/builders.json +24 -0
- package/builders/dev-server/index.js +82 -0
- package/builders/dev-server/schema.js +2 -0
- package/builders/dev-server/schema.json +28 -0
- package/builders/extract-i18n/index.js +70 -0
- package/builders/extract-i18n/schema.js +2 -0
- package/builders/extract-i18n/schema.json +49 -0
- package/builders/package.json +3 -0
- package/builders/project-import.js +64 -0
- package/builders/rspeedy.js +162 -0
- package/builders/unit-test/index.js +96 -0
- package/builders/unit-test/lynx-globals.d.mts +3 -0
- package/builders/unit-test/lynx-globals.mjs +18 -0
- package/builders/unit-test/schema.js +2 -0
- package/builders/unit-test/schema.json +311 -0
- package/client.d.ts +8 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +14 -0
- package/package.json +80 -4
package/README.md
CHANGED
|
@@ -1,3 +1,111 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @blotch/angular-lynx-build
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Angular CLI builders for [AngularLynx](https://github.com/Blotch-Smart-Frames/AngularLynx): `ng build`, `ng serve`, `ng test` and `ng extract-i18n` for Lynx, and `ng build --platform ios|android|all` for native apps.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
ng add @blotch/angular-lynx # installs this package and sets up angular.json
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
It is the only build dependency an AngularLynx app needs, as `@angular/build` is for a web app: it brings rspeedy, the rsbuild plugin that compiles Angular, the QR code plugin and the native app builder with it.
|
|
10
|
+
|
|
11
|
+
## Builders
|
|
12
|
+
|
|
13
|
+
```jsonc
|
|
14
|
+
// angular.json, as `ng add` writes it
|
|
15
|
+
"build": {
|
|
16
|
+
"builder": "@blotch/angular-lynx-build:application",
|
|
17
|
+
"options": { "browser": "src/main.ts", "tsConfig": "tsconfig.app.json" /* ... */ },
|
|
18
|
+
"configurations": {
|
|
19
|
+
"production": { "budgets": [/* ... */], "outputHashing": "all" },
|
|
20
|
+
"development": { "optimization": false, "extractLicenses": false, "sourceMap": true }
|
|
21
|
+
},
|
|
22
|
+
"defaultConfiguration": "production"
|
|
23
|
+
},
|
|
24
|
+
"serve": {
|
|
25
|
+
"builder": "@blotch/angular-lynx-build:dev-server",
|
|
26
|
+
"configurations": {
|
|
27
|
+
"production": { "buildTarget": "my-app:build:production" },
|
|
28
|
+
"development": { "buildTarget": "my-app:build:development" }
|
|
29
|
+
},
|
|
30
|
+
"defaultConfiguration": "development"
|
|
31
|
+
},
|
|
32
|
+
"test": {
|
|
33
|
+
"builder": "@blotch/angular-lynx-build:unit-test"
|
|
34
|
+
},
|
|
35
|
+
"extract-i18n": {
|
|
36
|
+
"builder": "@blotch/angular-lynx-build:extract-i18n"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| Builder | Command | What it does |
|
|
41
|
+
| -------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
42
|
+
| `application` | `ng build` | Builds the Lynx bundle (and the web preview bundle) into `dist/` with [rspeedy](https://lynxjs.org/rspeedy/) |
|
|
43
|
+
| | `ng build --watch` | Rebuilds the bundle whenever a file changes |
|
|
44
|
+
| | `ng build --platform ios` | Then builds the iOS app (`--platform android` or `all` for the others) into `dist/<platform>/` |
|
|
45
|
+
| `dev-server` | `ng serve` | Runs rspeedy's dev server for Lynx Explorer and the web preview, and prints the QR code Lynx Explorer scans |
|
|
46
|
+
| `unit-test` | `ng test` | Runs the unit tests with Angular's own unit-test builder (Vitest), set up for Lynx |
|
|
47
|
+
| `extract-i18n` | `ng extract-i18n` | Extracts the i18n messages with Angular's own extract-i18n builder, set up for Lynx |
|
|
48
|
+
|
|
49
|
+
They behave like Angular's own builders:
|
|
50
|
+
|
|
51
|
+
- **Configurations and overrides apply.** The build target's options reach the compiler as Angular CLI resolved them, so `ng build -c development` and flags like `--optimization=false` work.
|
|
52
|
+
- **`optimization` decides between a production and a development build.** There is no `mode` option: as in Angular, a build that optimizes scripts is a production build, and one that doesn't is a development build with dev mode on. `ng build -c development` is a development build, and `ng serve -c production` serves a production one.
|
|
53
|
+
- **`ng serve` builds its `buildTarget`**, by default the build target's `development` configuration. `--port` / `--host` override `server` in lynx.config.ts.
|
|
54
|
+
- **Budgets are enforced.** The `budgets` in the build target are checked against the Lynx bundle and the component stylesheets, with Angular's messages; `ng add` sizes the `initial` budget for a Lynx bundle. See the plugin's [README](../rsbuild-plugin-angular-lynx/README.md#budgets).
|
|
55
|
+
- **`--watch` rebuilds only the bundle.** It can't be combined with `--platform`: use `ng serve` while developing, and `ng build --platform` for the app.
|
|
56
|
+
|
|
57
|
+
The options are in [`builders/application/schema.json`](builders/application/schema.json), [`builders/dev-server/schema.json`](builders/dev-server/schema.json), [`builders/unit-test/schema.json`](builders/unit-test/schema.json) and [`builders/extract-i18n/schema.json`](builders/extract-i18n/schema.json).
|
|
58
|
+
|
|
59
|
+
## ng test
|
|
60
|
+
|
|
61
|
+
The `unit-test` builder is Angular's `@angular/build:unit-test`, set up for Lynx. Its options are Angular's (`include`, `watch`, `coverage`, `setupFiles`, `providersFile`, ...): its schema is a copy of Angular's, and a test keeps the two in step. It finds `*.spec.ts` and `*.test.ts` files, and the tests compile ahead of time, like the app. On top of Angular's setup it:
|
|
62
|
+
|
|
63
|
+
- defines the compile-time flags the AngularLynx runtime reads (`__DEV__`, `__MAIN_THREAD__`, ...), through a polyfill (`@blotch/angular-lynx-build/unit-test/lynx-globals`) that loads before anything else;
|
|
64
|
+
- loads `@blotch/angular-lynx-testing-library`'s setup when the project has the library, so its `render()` works with no setup file or Vitest config in the app;
|
|
65
|
+
- hands Angular the build target as an Angular one, with only the options both builders share, so Angular neither warns about an unknown builder nor rejects the Lynx-only options;
|
|
66
|
+
- loads imported images, fonts and media as file URLs, as rspeedy does in the app.
|
|
67
|
+
|
|
68
|
+
Two things work as in any Angular app, and differ from a plain Vitest setup:
|
|
69
|
+
|
|
70
|
+
- **Templates are checked strictly.** A component that uses Lynx elements imports `LYNX_ELEMENTS`, as the Angular Language Service already requires (generated components do). The app build is laxer: it adds `CUSTOM_ELEMENTS_SCHEMA` to every component, which Angular's test build has no hook for.
|
|
71
|
+
- **Test code is type-checked**, and test files share one module graph (Angular's runner isn't isolated by default). `vi.mock` of a relative import isn't supported, and mocking `@angular/core` would leak into other test files.
|
|
72
|
+
|
|
73
|
+
## ng extract-i18n
|
|
74
|
+
|
|
75
|
+
The `extract-i18n` builder is Angular's `@angular/build:extract-i18n`, set up for Lynx. Its options are Angular's (`format`, `outputPath`, `outFile`, ...), and, as for `ng test`, its schema is a copy of Angular's that a test keeps in step. Angular CLI picks an extractor by itself only for a project built with one of Angular's builders, so an AngularLynx app needs the target: `ng add` writes it, and `add-i18n` makes it write JSON to `src/locale`, which `loadTranslations()` takes.
|
|
76
|
+
|
|
77
|
+
Angular's extractor compiles the app with Angular's application builder. As in `ng test`, it gets the build target as an Angular one, and imported images, fonts and media load as file URLs: without a loader for them, Angular's build stops at the first imported image. Without `@angular/localize`, it says to run `add-i18n` rather than Angular's `ng add @angular/localize`, which only sets up Angular's own builders.
|
|
78
|
+
|
|
79
|
+
## lynx.config.ts
|
|
80
|
+
|
|
81
|
+
An app doesn't need one. Without it, `ng build` and `ng serve` take what rspeedy needs from angular.json and the defaults an AngularLynx app wants:
|
|
82
|
+
|
|
83
|
+
- `source.entry` is the build target's `browser` option;
|
|
84
|
+
- the environments are `lynx` (the native bundle) and `web` (the browser preview);
|
|
85
|
+
- `ng serve` adds the QR code plugin, in full screen.
|
|
86
|
+
|
|
87
|
+
Add a lynx.config.ts to change any of these or set anything else rspeedy supports; each default only applies where it doesn't set its own. The builders add [`@blotch/rsbuild-plugin-angular-lynx`](../rsbuild-plugin-angular-lynx), which compiles Angular, either way. List the plugin yourself only to pass it options. Import it and `defineConfig` from this package, which depends on both:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { defineConfig, pluginAngularLynx } from '@blotch/angular-lynx-build';
|
|
91
|
+
|
|
92
|
+
export default defineConfig({
|
|
93
|
+
plugins: [pluginAngularLynx({ enableSSR: true })],
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
For the types of what the bundler handles (asset and CSS module imports, `import.meta.env`), reference them from here too, as `ng add` does in `src/rspeedy-env.d.ts`:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
/// <reference types="@blotch/angular-lynx-build/client" />
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## How it's put together
|
|
104
|
+
|
|
105
|
+
This package is the Angular CLI layer. The work happens in its dependencies:
|
|
106
|
+
|
|
107
|
+
- **[`@blotch/rsbuild-plugin-angular-lynx`](../rsbuild-plugin-angular-lynx)** compiles Angular inside rspeedy. It also works on its own, for projects that run rspeedy directly.
|
|
108
|
+
- **[`@blotch/angular-lynx-native`](../native)** turns the Lynx bundle into iOS and Android apps.
|
|
109
|
+
- **[rspeedy](https://lynxjs.org/rspeedy/)** and its QR code plugin. The builders always run the versions they were released and tested with, so an app doesn't install them.
|
|
110
|
+
|
|
111
|
+
`ng test` and `ng extract-i18n` run Angular's builders from the project's own `@angular/build`, which `ng new` installs: it must match the project's Angular version.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asAngularBuildTargets = exports.ASSET_LOADERS = exports.ANGULAR_BUILD_OPTIONS = exports.importAngularBuild = void 0;
|
|
4
|
+
const project_import_1 = require("./project-import");
|
|
5
|
+
/**
|
|
6
|
+
* @angular/build comes from the project, like Angular's own builders: its
|
|
7
|
+
* version must match the project's Angular version, which `ng new` installs
|
|
8
|
+
* it for.
|
|
9
|
+
*/
|
|
10
|
+
const importAngularBuild = (projectRoot) => (0, project_import_1.importFromProject)('@angular/build', projectRoot, 'Run `npm install --save-dev @angular/build` (`ng new` adds it).');
|
|
11
|
+
exports.importAngularBuild = importAngularBuild;
|
|
12
|
+
const LYNX_APPLICATION_BUILDER = '@blotch/angular-lynx-build:application';
|
|
13
|
+
const ANGULAR_APPLICATION_BUILDER = '@angular/build:application';
|
|
14
|
+
/**
|
|
15
|
+
* The options of the Lynx application builder that are Angular's application
|
|
16
|
+
* builder's too, and mean the same. The rest (native app settings, rspeedy's
|
|
17
|
+
* `config` and `environment`) are Lynx-only; Angular's schema rejects them.
|
|
18
|
+
*/
|
|
19
|
+
exports.ANGULAR_BUILD_OPTIONS = [
|
|
20
|
+
'browser',
|
|
21
|
+
'tsConfig',
|
|
22
|
+
'polyfills',
|
|
23
|
+
'styles',
|
|
24
|
+
'assets',
|
|
25
|
+
'scripts',
|
|
26
|
+
'inlineStyleLanguage',
|
|
27
|
+
'fileReplacements',
|
|
28
|
+
'aot',
|
|
29
|
+
'optimization',
|
|
30
|
+
'sourceMap',
|
|
31
|
+
'outputHashing',
|
|
32
|
+
'i18nMissingTranslation',
|
|
33
|
+
'budgets',
|
|
34
|
+
'extractLicenses',
|
|
35
|
+
'outputPath',
|
|
36
|
+
'index',
|
|
37
|
+
'watch',
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* How Angular's build loads imported assets (`import logo from
|
|
41
|
+
* './logo.png'`): as files, so the import is the file's URL, as rspeedy
|
|
42
|
+
* makes it in the app. Angular's build has no loader for them by default and
|
|
43
|
+
* fails on the import.
|
|
44
|
+
*/
|
|
45
|
+
exports.ASSET_LOADERS = Object.fromEntries([
|
|
46
|
+
// Images
|
|
47
|
+
'png',
|
|
48
|
+
'jpg',
|
|
49
|
+
'jpeg',
|
|
50
|
+
'gif',
|
|
51
|
+
'webp',
|
|
52
|
+
'avif',
|
|
53
|
+
'bmp',
|
|
54
|
+
'ico',
|
|
55
|
+
'svg',
|
|
56
|
+
// Fonts
|
|
57
|
+
'woff',
|
|
58
|
+
'woff2',
|
|
59
|
+
'ttf',
|
|
60
|
+
'otf',
|
|
61
|
+
'eot',
|
|
62
|
+
// Audio and video
|
|
63
|
+
'mp4',
|
|
64
|
+
'webm',
|
|
65
|
+
'mov',
|
|
66
|
+
'mp3',
|
|
67
|
+
'wav',
|
|
68
|
+
'ogg',
|
|
69
|
+
'm4a',
|
|
70
|
+
'aac',
|
|
71
|
+
].map((extension) => [`.${extension}`, 'file']));
|
|
72
|
+
/**
|
|
73
|
+
* The builder context Angular's unit-test and extract-i18n builders get.
|
|
74
|
+
* Both compile the app with Angular's application builder, taking its
|
|
75
|
+
* options (tsconfig, polyfills, styles, file replacements) from the build
|
|
76
|
+
* target, and only know Angular's own application builder: for any other the
|
|
77
|
+
* unit-test builder warns that "unexpected behavior or build failures may
|
|
78
|
+
* occur", and both validate the options against that builder's schema. A
|
|
79
|
+
* Lynx build target therefore reaches them as an Angular one, with the
|
|
80
|
+
* options both builders share, which Angular's schema validates and
|
|
81
|
+
* completes with its defaults, the asset loaders rspeedy's defaults
|
|
82
|
+
* correspond to, and `lynxPolyfills` after the app's own polyfills.
|
|
83
|
+
*/
|
|
84
|
+
const asAngularBuildTargets = (context, lynxPolyfills = []) => {
|
|
85
|
+
const isLynxApplication = async (target) => (await context.getBuilderNameForTarget(target)) ===
|
|
86
|
+
LYNX_APPLICATION_BUILDER;
|
|
87
|
+
const overrides = {
|
|
88
|
+
getBuilderNameForTarget: async (target) => (await isLynxApplication(target))
|
|
89
|
+
? ANGULAR_APPLICATION_BUILDER
|
|
90
|
+
: context.getBuilderNameForTarget(target),
|
|
91
|
+
getTargetOptions: async (target) => {
|
|
92
|
+
const options = await context.getTargetOptions(target);
|
|
93
|
+
if (!(await isLynxApplication(target))) {
|
|
94
|
+
return options;
|
|
95
|
+
}
|
|
96
|
+
const polyfills = options['polyfills'];
|
|
97
|
+
return {
|
|
98
|
+
...Object.fromEntries(Object.entries(options).filter(([key]) => exports.ANGULAR_BUILD_OPTIONS.includes(key))),
|
|
99
|
+
loader: exports.ASSET_LOADERS,
|
|
100
|
+
polyfills: [
|
|
101
|
+
...(Array.isArray(polyfills)
|
|
102
|
+
? polyfills
|
|
103
|
+
: typeof polyfills === 'string'
|
|
104
|
+
? [polyfills]
|
|
105
|
+
: []),
|
|
106
|
+
...lynxPolyfills,
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
return new Proxy(context, {
|
|
112
|
+
get: (target, property) => property in overrides
|
|
113
|
+
? overrides[property]
|
|
114
|
+
: Reflect.get(target, property),
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
exports.asAngularBuildTargets = asAngularBuildTargets;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runApplication = void 0;
|
|
7
|
+
const architect_1 = require("@angular-devkit/architect");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const rspeedy_1 = require("../rspeedy");
|
|
11
|
+
const native_cache_1 = require("./native-cache");
|
|
12
|
+
/**
|
|
13
|
+
* Like the rsbuild plugin, the native builder is this package's own
|
|
14
|
+
* dependency, resolved from here. Imported only for `--platform`, so a plain
|
|
15
|
+
* bundle build never loads it.
|
|
16
|
+
*/
|
|
17
|
+
const importNative = () => import('@blotch/angular-lynx-native');
|
|
18
|
+
const defaultDeps = {
|
|
19
|
+
importRspeedy: rspeedy_1.importRspeedy,
|
|
20
|
+
importPlugin: rspeedy_1.importPlugin,
|
|
21
|
+
importNative,
|
|
22
|
+
};
|
|
23
|
+
const errorOutput = (error) => ({
|
|
24
|
+
success: false,
|
|
25
|
+
error: error instanceof Error ? error.message : String(error),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* `ng build`: builds the Lynx bundle with rspeedy, as `rspeedy build` would,
|
|
29
|
+
* then, with `--platform`, the native binaries. The Angular compile happens
|
|
30
|
+
* inside rspeedy (through @blotch/rsbuild-plugin-angular-lynx, which
|
|
31
|
+
* `createRspeedy` adds when lynx.config.ts doesn't), so this builder only
|
|
32
|
+
* orchestrates.
|
|
33
|
+
*
|
|
34
|
+
* With `--watch` it reports a result after every rebuild and keeps running
|
|
35
|
+
* until Angular CLI tears it down, as Angular's own application builder does.
|
|
36
|
+
*/
|
|
37
|
+
const runApplication = async function* (options, context, deps = defaultDeps) {
|
|
38
|
+
const projectName = context.target?.project;
|
|
39
|
+
if (!projectName) {
|
|
40
|
+
yield { success: false, error: 'The builder needs a project target.' };
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const metadata = await context.getProjectMetadata(projectName);
|
|
44
|
+
const projectRoot = node_path_1.default.join(context.workspaceRoot, metadata['root'] ?? '');
|
|
45
|
+
const platforms = options.platform === 'all'
|
|
46
|
+
? ['ios', 'android']
|
|
47
|
+
: options.platform
|
|
48
|
+
? [options.platform]
|
|
49
|
+
: [];
|
|
50
|
+
if (options.watch && platforms.length > 0) {
|
|
51
|
+
// A native app is built once from a finished bundle; rebuilding the
|
|
52
|
+
// Xcode or Gradle project on every save would take minutes each time.
|
|
53
|
+
yield {
|
|
54
|
+
success: false,
|
|
55
|
+
error: "--watch rebuilds only the Lynx bundle and can't be combined with --platform. Use `ng serve` while developing, and `ng build --platform` for the app.",
|
|
56
|
+
};
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
let rspeedy;
|
|
60
|
+
let native;
|
|
61
|
+
let workDir = '';
|
|
62
|
+
try {
|
|
63
|
+
// Load the native builder first, so a broken install fails before a
|
|
64
|
+
// minute of bundling rather than after it.
|
|
65
|
+
if (platforms.length > 0) {
|
|
66
|
+
native = await deps.importNative();
|
|
67
|
+
workDir = (0, native_cache_1.nativeCacheDir)({
|
|
68
|
+
metadata,
|
|
69
|
+
workspaceRoot: context.workspaceRoot,
|
|
70
|
+
projectRoot,
|
|
71
|
+
projectName,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
rspeedy = await (0, rspeedy_1.createRspeedy)({
|
|
75
|
+
rspeedy: await deps.importRspeedy(),
|
|
76
|
+
plugin: await deps.importPlugin(),
|
|
77
|
+
projectRoot,
|
|
78
|
+
// Angular CLI already merged these: base options, the configurations
|
|
79
|
+
// chosen with -c (or the default one), then command-line overrides.
|
|
80
|
+
angularCli: {
|
|
81
|
+
workspaceRoot: context.workspaceRoot,
|
|
82
|
+
project: projectName,
|
|
83
|
+
buildOptions: options,
|
|
84
|
+
},
|
|
85
|
+
config: options.config,
|
|
86
|
+
// Native shells only load the Lynx bundle; skipping the web
|
|
87
|
+
// environment halves the bundling time.
|
|
88
|
+
environment: platforms.length > 0 ? ['lynx'] : options.environment,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
yield errorOutput(error);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (options.watch) {
|
|
96
|
+
yield* watchBundle(rspeedy, context);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
context.reportStatus('Building the Lynx bundle');
|
|
101
|
+
const { close } = await rspeedy.build();
|
|
102
|
+
await close();
|
|
103
|
+
const bundleDir = rspeedy.context.distPath;
|
|
104
|
+
for (const platform of platforms) {
|
|
105
|
+
context.reportStatus(`Building the ${platform} app`);
|
|
106
|
+
const { artifacts } = await native.buildNativeApp({
|
|
107
|
+
platform,
|
|
108
|
+
projectRoot,
|
|
109
|
+
workDir,
|
|
110
|
+
projectName,
|
|
111
|
+
packageVersion: readPackageVersion(projectRoot),
|
|
112
|
+
bundleDir,
|
|
113
|
+
outputDir: node_path_1.default.join(bundleDir, platform),
|
|
114
|
+
app: options,
|
|
115
|
+
log: (message) => context.logger.info(message),
|
|
116
|
+
});
|
|
117
|
+
for (const artifact of artifacts) {
|
|
118
|
+
context.logger.info(` ✓ ${node_path_1.default.relative(context.workspaceRoot, artifact)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
yield { success: true };
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
yield errorOutput(error);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
exports.runApplication = runApplication;
|
|
128
|
+
/**
|
|
129
|
+
* `ng build --watch`: rspeedy's watch build, reporting each compile's result.
|
|
130
|
+
* Compile errors fail that result but keep watching, as in Angular, so the
|
|
131
|
+
* next save can fix them. Angular CLI ends the run (Ctrl+C) through the
|
|
132
|
+
* teardown, which stops the watcher.
|
|
133
|
+
*/
|
|
134
|
+
const watchBundle = async function* (rspeedy, context) {
|
|
135
|
+
const results = [];
|
|
136
|
+
let wake;
|
|
137
|
+
rspeedy.onAfterBuild(({ stats }) => {
|
|
138
|
+
results.push({ success: !stats?.hasErrors() });
|
|
139
|
+
wake?.();
|
|
140
|
+
});
|
|
141
|
+
try {
|
|
142
|
+
context.reportStatus('Watching the Lynx bundle');
|
|
143
|
+
const { close } = await rspeedy.build({ watch: true });
|
|
144
|
+
context.addTeardown(close);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
yield errorOutput(error);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
for (;;) {
|
|
151
|
+
while (results.length > 0) {
|
|
152
|
+
yield results.shift();
|
|
153
|
+
}
|
|
154
|
+
await new Promise((resolve) => (wake = resolve));
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const readPackageVersion = (projectRoot) => {
|
|
158
|
+
try {
|
|
159
|
+
return JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(projectRoot, 'package.json'), 'utf8')).version;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
exports.default = (0, architect_1.createBuilder)((options, context) => (0, exports.runApplication)(options, context));
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.nativeCacheDir = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_module_1 = require("node:module");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
/**
|
|
11
|
+
* Where `ng build --platform` keeps the generated Xcode and Gradle projects,
|
|
12
|
+
* their build state and the logs: the project's folder in Angular's build
|
|
13
|
+
* cache, `.angular/cache/<Angular version>/<project>/lynx-native` by default.
|
|
14
|
+
*
|
|
15
|
+
* Inside Angular's cache rather than a folder of our own at the project
|
|
16
|
+
* root, so a Lynx app's root looks like any Angular app's: `ng new` already
|
|
17
|
+
* git-ignores the cache, `ng cache clean` clears it, and `cli.cache.path`
|
|
18
|
+
* moves it.
|
|
19
|
+
*
|
|
20
|
+
* The version folder isn't optional. Angular's application and dev-server
|
|
21
|
+
* builders delete every folder in the cache except the current version's,
|
|
22
|
+
* so a `lynx-native` folder beside it would be deleted by the next Angular
|
|
23
|
+
* build. Under it, an Angular update clears the native projects too, which
|
|
24
|
+
* costs one regeneration.
|
|
25
|
+
*
|
|
26
|
+
* Angular shares one cache between a repository's linked checkouts, using
|
|
27
|
+
* the main checkout's. This stays in the current checkout instead: two
|
|
28
|
+
* checkouts building at once would overwrite each other's generated
|
|
29
|
+
* project. And it's used even when `cli.cache.enabled` is
|
|
30
|
+
* false, because the native build needs a working folder either way.
|
|
31
|
+
*/
|
|
32
|
+
const nativeCacheDir = ({ metadata, workspaceRoot, projectRoot, projectName, }) => node_path_1.default.join(node_path_1.default.resolve(workspaceRoot, cachePath(metadata)), angularBuildVersion(projectRoot), projectName, 'lynx-native');
|
|
33
|
+
exports.nativeCacheDir = nativeCacheDir;
|
|
34
|
+
/**
|
|
35
|
+
* angular.json's `cli.cache.path`, defaulting as Angular does.
|
|
36
|
+
*/
|
|
37
|
+
const cachePath = (metadata) => {
|
|
38
|
+
const cli = metadata['cli'];
|
|
39
|
+
const value = cli?.cache?.path;
|
|
40
|
+
return typeof value === 'string' ? value : '.angular/cache';
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The version Angular names its cache folder after: @angular/build's, which
|
|
44
|
+
* this package needs as a peer dependency (`ng new` installs it).
|
|
45
|
+
*/
|
|
46
|
+
const angularBuildVersion = (projectRoot) => {
|
|
47
|
+
const require = (0, node_module_1.createRequire)(node_path_1.default.join(projectRoot, 'package.json'));
|
|
48
|
+
let packageJsonPath;
|
|
49
|
+
try {
|
|
50
|
+
packageJsonPath = require.resolve('@angular/build/package.json');
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new Error('@angular/build is not installed. Run `npm install --save-dev @angular/build` (`ng new` adds it).');
|
|
54
|
+
}
|
|
55
|
+
return JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf8')).version;
|
|
56
|
+
};
|