@richapps/ong 0.1.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/README.md +166 -0
- package/bin/ong.js +5 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +83 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +89 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +12 -0
- package/dist/log.d.ts +16 -0
- package/dist/log.js +96 -0
- package/dist/plugins.d.ts +11 -0
- package/dist/plugins.js +97 -0
- package/dist/workspace.d.ts +125 -0
- package/dist/workspace.js +232 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="ong-logo.png" alt="ong" width="200">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">@richapps/ong</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Angular CLI powered by <a href="https://vite.dev">Vite</a> + <a href="https://github.com/nicoss/oxc-angular-compiler">OXC</a><br>
|
|
9
|
+
<em>Blazing fast drop-in replacement for <code>ng serve</code> and <code>ng build</code></em>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What is ong?
|
|
15
|
+
|
|
16
|
+
**ong** uses the Rust-based [OXC Angular compiler](https://github.com/nicoss/oxc-angular-compiler) and [Vite](https://vite.dev) to compile and serve Angular applications — no Webpack, no esbuild, just raw speed.
|
|
17
|
+
|
|
18
|
+
It reads your existing `angular.json` (or Nx `project.json`) and works with a standard Angular project out of the box. No config files to write, no migration steps.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -D @richapps/ong
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If you already have `vite` installed, ong will use your version. Otherwise it will be auto-installed as a peer dependency.
|
|
27
|
+
|
|
28
|
+
For global usage:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install -g @richapps/ong
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Start dev server
|
|
38
|
+
ong serve
|
|
39
|
+
|
|
40
|
+
# Production build
|
|
41
|
+
ong build
|
|
42
|
+
|
|
43
|
+
# With options
|
|
44
|
+
ong serve --port 3000 --open
|
|
45
|
+
ong build -c production
|
|
46
|
+
ong serve -p my-app # specific project
|
|
47
|
+
ong build -p apps/my-app # nx project path
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or via npm scripts in `package.json`:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"scripts": {
|
|
55
|
+
"start": "ong serve",
|
|
56
|
+
"build": "ong build"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## CLI Options
|
|
62
|
+
|
|
63
|
+
| Option | Alias | Description |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `--configuration <name>` | `-c` | Build configuration (default: per-target default) |
|
|
66
|
+
| `--project <name\|path>` | `-p` | Project name (angular.json) or path (nx project.json) |
|
|
67
|
+
| `--port <number>` | | Dev server port (default: 4200) |
|
|
68
|
+
| `--open` | `-o` | Open browser on start |
|
|
69
|
+
| `--host <host>` | | Dev server host |
|
|
70
|
+
| `--watch` | `-w` | Rebuild on file changes (build mode) |
|
|
71
|
+
| `--help` | `-h` | Show help |
|
|
72
|
+
|
|
73
|
+
## Workspace Support
|
|
74
|
+
|
|
75
|
+
ong auto-detects your workspace type:
|
|
76
|
+
|
|
77
|
+
- **angular.json** — Standard Angular CLI workspace
|
|
78
|
+
- **workspace.json** — Older Nx workspace format
|
|
79
|
+
- **project.json** — Per-project Nx monorepo setup
|
|
80
|
+
|
|
81
|
+
Configurations, file replacements, global styles/scripts, and assets are all read from your existing workspace config.
|
|
82
|
+
|
|
83
|
+
## Supported angular.json / project.json Properties
|
|
84
|
+
|
|
85
|
+
### Build target options
|
|
86
|
+
|
|
87
|
+
| Property | Status | Notes |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `browser` / `main` | Supported | Entry point |
|
|
90
|
+
| `tsConfig` | Supported | |
|
|
91
|
+
| `outputPath` | Supported | |
|
|
92
|
+
| `assets` | Supported | String and object (`glob`/`input`/`output`) forms |
|
|
93
|
+
| `styles` | Supported | Global stylesheets, string and `{ input }` forms |
|
|
94
|
+
| `scripts` | Supported | Global scripts |
|
|
95
|
+
| `fileReplacements` | Supported | `replace`/`with` pairs |
|
|
96
|
+
| `sourceMap` | Supported | |
|
|
97
|
+
| `optimization` | Supported | Uses OXC minifier |
|
|
98
|
+
| `outputHashing` | Supported | `none`, `all`, `media`, `bundles` |
|
|
99
|
+
| `configurations` | Supported | Merges base + per-config overrides |
|
|
100
|
+
| `defaultConfiguration` | Supported | |
|
|
101
|
+
| `baseHref` | Supported | Injected into `<base href="...">` and used as Vite `base` |
|
|
102
|
+
| `deployUrl` | Supported | Maps to Vite `base` (takes precedence over `baseHref`) |
|
|
103
|
+
| `polyfills` | Supported | Injected as `<script>` tags (string or array) |
|
|
104
|
+
| `define` | Supported | Maps to Vite `define` for global constant replacements |
|
|
105
|
+
| `externalDependencies` | Supported | Maps to Rollup `external` |
|
|
106
|
+
| `preserveSymlinks` | Supported | Maps to Vite `resolve.preserveSymlinks` |
|
|
107
|
+
| `namedChunks` | Supported | Disables hash-based chunk naming |
|
|
108
|
+
| `crossOrigin` | Supported | Sets attribute on injected `<script>`/`<link>` tags |
|
|
109
|
+
| `stylePreprocessorOptions` | Supported | `includePaths` mapped to Vite `css.preprocessorOptions` |
|
|
110
|
+
| `watch` | Supported | Maps to Vite `build.watch` (also via `--watch` CLI flag) |
|
|
111
|
+
| `poll` | Supported | Maps to Vite `server.watch.usePolling` with interval |
|
|
112
|
+
|
|
113
|
+
### Serve target options
|
|
114
|
+
|
|
115
|
+
| Property | Status | Notes |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `port` | Supported | |
|
|
118
|
+
| `open` | Supported | |
|
|
119
|
+
| `host` | Supported | |
|
|
120
|
+
| `poll` | Supported | File-watching poll interval |
|
|
121
|
+
| `buildTarget` | Ignored | Configuration is resolved from the build target directly |
|
|
122
|
+
|
|
123
|
+
### Not yet supported
|
|
124
|
+
|
|
125
|
+
These `@angular/build:application` properties are **not currently handled** — they are silently ignored:
|
|
126
|
+
|
|
127
|
+
| Property | Description |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `budgets` | Bundle size budgets and warnings |
|
|
130
|
+
| `extractLicenses` | Extract third-party licenses to a separate file |
|
|
131
|
+
| `subresourceIntegrity` | SRI hashes on `<script>`/`<link>` tags |
|
|
132
|
+
| `allowedCommonJsDependencies` | Suppress CommonJS import warnings |
|
|
133
|
+
| `serviceWorker` / `ngswConfigPath` | PWA service worker generation |
|
|
134
|
+
| `webWorkerTsConfig` | Separate tsconfig for web workers |
|
|
135
|
+
| `i18nMissingTranslation` | i18n missing translation handling |
|
|
136
|
+
| `localize` | i18n locale builds |
|
|
137
|
+
| `inlineStyleLanguage` | Default preprocessor for inline component styles |
|
|
138
|
+
| `loader` | Custom file extension loaders |
|
|
139
|
+
| `progress` | Show build progress indicator |
|
|
140
|
+
| `ssr` / `server` / `prerender` | Server-side rendering / prerendering |
|
|
141
|
+
| `security` | Content Security Policy settings |
|
|
142
|
+
|
|
143
|
+
> SSR support is not planned — ong focuses on client-side Angular applications.
|
|
144
|
+
|
|
145
|
+
## Programmatic API
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { resolveWorkspace, createViteConfig } from '@richapps/ong'
|
|
149
|
+
|
|
150
|
+
const opts = resolveWorkspace(process.cwd(), {
|
|
151
|
+
command: 'build',
|
|
152
|
+
configuration: 'production',
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
const viteConfig = createViteConfig(opts)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Requirements
|
|
159
|
+
|
|
160
|
+
- Node.js 18+
|
|
161
|
+
- Angular 17+ (standalone components recommended)
|
|
162
|
+
- Vite 6+
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
package/bin/ong.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createServer, build } from 'vite';
|
|
2
|
+
import { resolveWorkspace } from './workspace.js';
|
|
3
|
+
import { createViteConfig } from './config.js';
|
|
4
|
+
import { banner, printBuildStats, printHelp, error } from './log.js';
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const args = argv.slice(2);
|
|
7
|
+
const command = args[0];
|
|
8
|
+
if (!command || !['serve', 'build'].includes(command)) {
|
|
9
|
+
return { command: 'help' };
|
|
10
|
+
}
|
|
11
|
+
const result = { command };
|
|
12
|
+
for (let i = 1; i < args.length; i++) {
|
|
13
|
+
const arg = args[i];
|
|
14
|
+
const next = args[i + 1];
|
|
15
|
+
if (arg === '--project' || arg === '-p') {
|
|
16
|
+
result.project = next;
|
|
17
|
+
i++;
|
|
18
|
+
}
|
|
19
|
+
else if (arg === '--configuration' || arg === '-c') {
|
|
20
|
+
result.configuration = next;
|
|
21
|
+
i++;
|
|
22
|
+
}
|
|
23
|
+
else if (arg.startsWith('--configuration=')) {
|
|
24
|
+
result.configuration = arg.split('=')[1];
|
|
25
|
+
}
|
|
26
|
+
else if (arg === '--port') {
|
|
27
|
+
result.port = parseInt(next);
|
|
28
|
+
i++;
|
|
29
|
+
}
|
|
30
|
+
else if (arg === '--open' || arg === '-o') {
|
|
31
|
+
result.open = true;
|
|
32
|
+
}
|
|
33
|
+
else if (arg === '--host') {
|
|
34
|
+
result.host = next;
|
|
35
|
+
i++;
|
|
36
|
+
}
|
|
37
|
+
else if (arg === '--watch' || arg === '-w') {
|
|
38
|
+
result.watch = true;
|
|
39
|
+
}
|
|
40
|
+
else if (arg === '--help' || arg === '-h') {
|
|
41
|
+
return { command: 'help' };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
// ═══════════════════════════════════════════════════════════════
|
|
47
|
+
// Main
|
|
48
|
+
// ═══════════════════════════════════════════════════════════════
|
|
49
|
+
async function main() {
|
|
50
|
+
const args = parseArgs(process.argv);
|
|
51
|
+
if (args.command === 'help') {
|
|
52
|
+
printHelp();
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
const cwd = process.cwd();
|
|
56
|
+
const resolveOpts = {
|
|
57
|
+
command: args.command,
|
|
58
|
+
project: args.project,
|
|
59
|
+
configuration: args.configuration,
|
|
60
|
+
port: args.port,
|
|
61
|
+
open: args.open,
|
|
62
|
+
host: args.host,
|
|
63
|
+
watch: args.watch,
|
|
64
|
+
};
|
|
65
|
+
const buildOpts = resolveWorkspace(cwd, resolveOpts);
|
|
66
|
+
banner(args.command, buildOpts.projectName, buildOpts.configName);
|
|
67
|
+
const viteConfig = createViteConfig(buildOpts);
|
|
68
|
+
if (args.command === 'serve') {
|
|
69
|
+
const server = await createServer(viteConfig);
|
|
70
|
+
await server.listen();
|
|
71
|
+
server.printUrls();
|
|
72
|
+
console.log();
|
|
73
|
+
}
|
|
74
|
+
if (args.command === 'build') {
|
|
75
|
+
const start = Date.now();
|
|
76
|
+
await build(viteConfig);
|
|
77
|
+
const duration = Date.now() - start;
|
|
78
|
+
printBuildStats(buildOpts.outputPath, duration);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
main().catch(err => {
|
|
82
|
+
error(err.message);
|
|
83
|
+
});
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { angular } from '@oxc-angular/vite';
|
|
3
|
+
import { htmlInjectPlugin, assetCopyPlugin } from './plugins.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Vite InlineConfig from resolved Angular build options.
|
|
6
|
+
*/
|
|
7
|
+
export function createViteConfig(opts) {
|
|
8
|
+
const { workspaceRoot, sourceRoot } = opts;
|
|
9
|
+
// Output naming based on hashing config
|
|
10
|
+
const hash = (scope) => {
|
|
11
|
+
if (opts.outputHashing === 'all')
|
|
12
|
+
return true;
|
|
13
|
+
if (opts.outputHashing === 'none')
|
|
14
|
+
return false;
|
|
15
|
+
if (opts.outputHashing === 'media' && scope === 'asset')
|
|
16
|
+
return true;
|
|
17
|
+
if (opts.outputHashing === 'bundles' && scope === 'chunk')
|
|
18
|
+
return true;
|
|
19
|
+
return false;
|
|
20
|
+
};
|
|
21
|
+
// namedChunks overrides hash-based naming for JS chunks
|
|
22
|
+
const useChunkHash = !opts.namedChunks && hash('chunk');
|
|
23
|
+
const assetNames = hash('asset') ? 'assets/[name]-[hash].[ext]' : 'assets/[name].[ext]';
|
|
24
|
+
const chunkNames = useChunkHash ? 'assets/[name]-[hash].js' : 'assets/[name].js';
|
|
25
|
+
const entryNames = useChunkHash ? '[name]-[hash].js' : '[name].js';
|
|
26
|
+
// deployUrl takes precedence over baseHref for Vite's base
|
|
27
|
+
const base = opts.deployUrl || opts.baseHref || '/';
|
|
28
|
+
// Sass/Less includePaths → Vite css.preprocessorOptions
|
|
29
|
+
const cssPreprocessorOptions = {};
|
|
30
|
+
if (opts.stylePreprocessorOptions.includePaths.length) {
|
|
31
|
+
const paths = opts.stylePreprocessorOptions.includePaths;
|
|
32
|
+
cssPreprocessorOptions.scss = { includePaths: paths };
|
|
33
|
+
cssPreprocessorOptions.sass = { includePaths: paths };
|
|
34
|
+
cssPreprocessorOptions.less = { paths };
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
root: resolve(workspaceRoot, sourceRoot),
|
|
38
|
+
base,
|
|
39
|
+
publicDir: resolve(workspaceRoot, 'public'),
|
|
40
|
+
logLevel: 'info',
|
|
41
|
+
plugins: [
|
|
42
|
+
htmlInjectPlugin(opts),
|
|
43
|
+
...angular({
|
|
44
|
+
tsconfig: opts.tsconfig,
|
|
45
|
+
sourceMap: opts.sourceMap,
|
|
46
|
+
liveReload: !opts.optimization,
|
|
47
|
+
workspaceRoot,
|
|
48
|
+
...(opts.fileReplacements.length ? { fileReplacements: opts.fileReplacements } : {}),
|
|
49
|
+
}),
|
|
50
|
+
assetCopyPlugin(opts.assets, workspaceRoot, sourceRoot),
|
|
51
|
+
],
|
|
52
|
+
// Global constant replacements (angular.json "define")
|
|
53
|
+
...(Object.keys(opts.define).length ? { define: opts.define } : {}),
|
|
54
|
+
resolve: {
|
|
55
|
+
preserveSymlinks: opts.preserveSymlinks,
|
|
56
|
+
},
|
|
57
|
+
css: Object.keys(cssPreprocessorOptions).length
|
|
58
|
+
? { preprocessorOptions: cssPreprocessorOptions }
|
|
59
|
+
: undefined,
|
|
60
|
+
build: {
|
|
61
|
+
outDir: opts.outputPath,
|
|
62
|
+
emptyOutDir: true,
|
|
63
|
+
sourcemap: opts.sourceMap,
|
|
64
|
+
minify: opts.optimization ? 'oxc' : false,
|
|
65
|
+
modulePreload: { polyfill: false },
|
|
66
|
+
watch: opts.watch ? {} : null,
|
|
67
|
+
rollupOptions: {
|
|
68
|
+
// Use index.html as entry so Vite processes HTML transforms (script/style injection)
|
|
69
|
+
input: resolve(workspaceRoot, sourceRoot, 'index.html'),
|
|
70
|
+
external: opts.externalDependencies.length ? opts.externalDependencies : undefined,
|
|
71
|
+
},
|
|
72
|
+
assetsInlineLimit: 0,
|
|
73
|
+
rolldownOptions: {
|
|
74
|
+
tsconfig: opts.tsconfig,
|
|
75
|
+
output: {
|
|
76
|
+
assetFileNames: assetNames,
|
|
77
|
+
chunkFileNames: chunkNames,
|
|
78
|
+
entryFileNames: entryNames,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
server: {
|
|
83
|
+
port: opts.serve.port,
|
|
84
|
+
open: opts.serve.open,
|
|
85
|
+
host: opts.serve.host ?? false,
|
|
86
|
+
watch: opts.poll ? { usePolling: true, interval: opts.poll } : undefined,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic API for @richapps/ong
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { resolveWorkspace, createViteConfig } from '@richapps/ong'
|
|
6
|
+
*
|
|
7
|
+
* const opts = resolveWorkspace(process.cwd(), { command: 'build', configuration: 'production' })
|
|
8
|
+
* const viteConfig = createViteConfig(opts)
|
|
9
|
+
*/
|
|
10
|
+
export { resolveWorkspace, detectWorkspace } from './workspace.js';
|
|
11
|
+
export type { ResolvedBuildOptions, ResolveOptions, AssetConfig } from './workspace.js';
|
|
12
|
+
export { createViteConfig } from './config.js';
|
|
13
|
+
export { htmlInjectPlugin, assetCopyPlugin } from './plugins.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Programmatic API for @richapps/ong
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { resolveWorkspace, createViteConfig } from '@richapps/ong'
|
|
6
|
+
*
|
|
7
|
+
* const opts = resolveWorkspace(process.cwd(), { command: 'build', configuration: 'production' })
|
|
8
|
+
* const viteConfig = createViteConfig(opts)
|
|
9
|
+
*/
|
|
10
|
+
export { resolveWorkspace, detectWorkspace } from './workspace.js';
|
|
11
|
+
export { createViteConfig } from './config.js';
|
|
12
|
+
export { htmlInjectPlugin, assetCopyPlugin } from './plugins.js';
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare const c: {
|
|
2
|
+
reset: string;
|
|
3
|
+
bold: string;
|
|
4
|
+
dim: string;
|
|
5
|
+
green: string;
|
|
6
|
+
cyan: string;
|
|
7
|
+
yellow: string;
|
|
8
|
+
red: string;
|
|
9
|
+
gray: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function banner(command: string, projectName: string, configName: string): void;
|
|
12
|
+
export declare function error(msg: string): never;
|
|
13
|
+
export declare function formatBytes(bytes: number): string;
|
|
14
|
+
export declare function printBuildStats(outDir: string, durationMs: number): void;
|
|
15
|
+
export declare function printHelp(): void;
|
|
16
|
+
export { c };
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
const c = {
|
|
4
|
+
reset: '\x1b[0m',
|
|
5
|
+
bold: '\x1b[1m',
|
|
6
|
+
dim: '\x1b[2m',
|
|
7
|
+
green: '\x1b[32m',
|
|
8
|
+
cyan: '\x1b[36m',
|
|
9
|
+
yellow: '\x1b[33m',
|
|
10
|
+
red: '\x1b[31m',
|
|
11
|
+
gray: '\x1b[90m',
|
|
12
|
+
};
|
|
13
|
+
export function banner(command, projectName, configName) {
|
|
14
|
+
console.log();
|
|
15
|
+
console.log(` ${c.green}${c.bold}ong${c.reset} ${c.dim}— Angular + OXC + Vite${c.reset}`);
|
|
16
|
+
console.log();
|
|
17
|
+
console.log(` ${c.dim}Command:${c.reset} ${command}`);
|
|
18
|
+
console.log(` ${c.dim}Project:${c.reset} ${projectName}`);
|
|
19
|
+
console.log(` ${c.dim}Configuration:${c.reset} ${configName}`);
|
|
20
|
+
console.log();
|
|
21
|
+
}
|
|
22
|
+
export function error(msg) {
|
|
23
|
+
console.error(`\n ${c.red}${c.bold}Error:${c.reset} ${msg}\n`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
export function formatBytes(bytes) {
|
|
27
|
+
if (bytes < 1024)
|
|
28
|
+
return bytes + ' B';
|
|
29
|
+
if (bytes < 1024 * 1024)
|
|
30
|
+
return (bytes / 1024).toFixed(1) + ' kB';
|
|
31
|
+
return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
|
|
32
|
+
}
|
|
33
|
+
export function printBuildStats(outDir, durationMs) {
|
|
34
|
+
console.log();
|
|
35
|
+
console.log(` ${c.green}${c.bold}Build complete${c.reset} in ${c.bold}${durationMs}ms${c.reset}`);
|
|
36
|
+
console.log(` ${c.dim}Output:${c.reset} ${relative(process.cwd(), outDir)}`);
|
|
37
|
+
console.log();
|
|
38
|
+
try {
|
|
39
|
+
const files = readdirSync(outDir, { recursive: true, withFileTypes: true });
|
|
40
|
+
const entries = [];
|
|
41
|
+
for (const f of files) {
|
|
42
|
+
if (f.isFile()) {
|
|
43
|
+
const fullPath = join(f.parentPath ?? f.path, f.name);
|
|
44
|
+
const stat = statSync(fullPath);
|
|
45
|
+
entries.push({ path: relative(outDir, fullPath), size: stat.size });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
entries.sort((a, b) => b.size - a.size);
|
|
49
|
+
const totalSize = entries.reduce((sum, e) => sum + e.size, 0);
|
|
50
|
+
for (const entry of entries.slice(0, 15)) {
|
|
51
|
+
const sizeStr = formatBytes(entry.size).padStart(10);
|
|
52
|
+
const isJs = entry.path.endsWith('.js');
|
|
53
|
+
const isCss = entry.path.endsWith('.css');
|
|
54
|
+
const color = isJs ? c.yellow : isCss ? c.cyan : c.dim;
|
|
55
|
+
console.log(` ${color}${sizeStr}${c.reset} ${entry.path}`);
|
|
56
|
+
}
|
|
57
|
+
if (entries.length > 15) {
|
|
58
|
+
console.log(` ${c.dim}... and ${entries.length - 15} more files${c.reset}`);
|
|
59
|
+
}
|
|
60
|
+
console.log();
|
|
61
|
+
console.log(` ${c.bold}Total: ${formatBytes(totalSize)}${c.reset}`);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// ignore
|
|
65
|
+
}
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
export function printHelp() {
|
|
69
|
+
console.log(`
|
|
70
|
+
${c.green}${c.bold}ong${c.reset} ${c.dim}— Angular CLI powered by Vite + OXC${c.reset}
|
|
71
|
+
|
|
72
|
+
${c.bold}Commands:${c.reset}
|
|
73
|
+
serve Start dev server
|
|
74
|
+
build Build for production
|
|
75
|
+
|
|
76
|
+
${c.bold}Options:${c.reset}
|
|
77
|
+
-c, --configuration <name> Build configuration (default: per-target default)
|
|
78
|
+
-p, --project <name> Project name (angular.json) or path (nx project.json)
|
|
79
|
+
--port <number> Dev server port (default: 4200)
|
|
80
|
+
-o, --open Open browser on start
|
|
81
|
+
--host <host> Dev server host
|
|
82
|
+
-w, --watch Rebuild on file changes (build mode)
|
|
83
|
+
|
|
84
|
+
${c.bold}Workspace support:${c.reset}
|
|
85
|
+
angular.json Standard Angular CLI workspace
|
|
86
|
+
project.json Nx monorepo (auto-detected)
|
|
87
|
+
|
|
88
|
+
${c.bold}Examples:${c.reset}
|
|
89
|
+
ong serve
|
|
90
|
+
ong build -c production
|
|
91
|
+
ong serve --port 3000 --open
|
|
92
|
+
ong build -p my-app -c production
|
|
93
|
+
ong serve -p apps/my-app ${c.dim}# nx project path${c.reset}
|
|
94
|
+
`);
|
|
95
|
+
}
|
|
96
|
+
export { c };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import type { ResolvedBuildOptions, AssetConfig } from './workspace.js';
|
|
3
|
+
/**
|
|
4
|
+
* Injects global styles, scripts, polyfills, and the entry point into index.html.
|
|
5
|
+
* This makes a standard Angular index.html work with Vite without modifications.
|
|
6
|
+
*/
|
|
7
|
+
export declare function htmlInjectPlugin(opts: ResolvedBuildOptions): Plugin;
|
|
8
|
+
/**
|
|
9
|
+
* Copies static assets from angular.json config to build output.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assetCopyPlugin(assets: AssetConfig[], workspaceRoot: string, sourceRoot: string): Plugin;
|
package/dist/plugins.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { existsSync, cpSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { resolve, relative, join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Injects global styles, scripts, polyfills, and the entry point into index.html.
|
|
5
|
+
* This makes a standard Angular index.html work with Vite without modifications.
|
|
6
|
+
*/
|
|
7
|
+
export function htmlInjectPlugin(opts) {
|
|
8
|
+
const viteRoot = resolve(opts.workspaceRoot, opts.sourceRoot);
|
|
9
|
+
const browserRelative = '/' + relative(viteRoot, opts.browser);
|
|
10
|
+
const styleRefs = opts.styles.map(s => '/' + relative(viteRoot, s));
|
|
11
|
+
const scriptRefs = opts.scripts.map(s => '/' + relative(viteRoot, s));
|
|
12
|
+
const crossOriginAttr = opts.crossOrigin !== 'none'
|
|
13
|
+
? ` crossorigin="${opts.crossOrigin}"`
|
|
14
|
+
: '';
|
|
15
|
+
return {
|
|
16
|
+
name: 'ong:html-inject',
|
|
17
|
+
transformIndexHtml: {
|
|
18
|
+
order: 'pre',
|
|
19
|
+
handler(html) {
|
|
20
|
+
let result = html;
|
|
21
|
+
// Inject/update base href if not default
|
|
22
|
+
if (opts.baseHref && opts.baseHref !== '/') {
|
|
23
|
+
if (result.includes('<base href=')) {
|
|
24
|
+
result = result.replace(/<base href="[^"]*">/, `<base href="${opts.baseHref}">`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
result = result.replace('<head>', `<head>\n <base href="${opts.baseHref}">`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Inject global stylesheets
|
|
31
|
+
if (styleRefs.length) {
|
|
32
|
+
const tags = styleRefs
|
|
33
|
+
.map(s => ` <link rel="stylesheet" href="${s}"${crossOriginAttr}>`)
|
|
34
|
+
.join('\n');
|
|
35
|
+
result = result.replace('</head>', `${tags}\n</head>`);
|
|
36
|
+
}
|
|
37
|
+
// Inject global scripts
|
|
38
|
+
if (scriptRefs.length) {
|
|
39
|
+
const tags = scriptRefs
|
|
40
|
+
.map(s => ` <script type="module" src="${s}"${crossOriginAttr}></script>`)
|
|
41
|
+
.join('\n');
|
|
42
|
+
result = result.replace('</head>', `${tags}\n</head>`);
|
|
43
|
+
}
|
|
44
|
+
// Inject polyfills before the entry point
|
|
45
|
+
if (opts.polyfills.length) {
|
|
46
|
+
const tags = opts.polyfills
|
|
47
|
+
.map(p => {
|
|
48
|
+
// Bare specifiers (e.g. "zone.js") become imports, paths become src refs
|
|
49
|
+
if (p.startsWith('.') || p.startsWith('/')) {
|
|
50
|
+
const ref = '/' + relative(viteRoot, resolve(opts.workspaceRoot, p));
|
|
51
|
+
return ` <script type="module" src="${ref}"${crossOriginAttr}></script>`;
|
|
52
|
+
}
|
|
53
|
+
return ` <script type="module">import '${p}';</script>`;
|
|
54
|
+
})
|
|
55
|
+
.join('\n');
|
|
56
|
+
result = result.replace('</body>', `${tags}\n</body>`);
|
|
57
|
+
}
|
|
58
|
+
// Inject entry point if not already present
|
|
59
|
+
const hasEntry = html.includes(`src="${browserRelative}"`) ||
|
|
60
|
+
html.includes('src="/main.ts"') ||
|
|
61
|
+
html.includes('src="main.ts"');
|
|
62
|
+
if (!hasEntry) {
|
|
63
|
+
result = result.replace('</body>', ` <script type="module" src="${browserRelative}"${crossOriginAttr}></script>\n</body>`);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Copies static assets from angular.json config to build output.
|
|
72
|
+
*/
|
|
73
|
+
export function assetCopyPlugin(assets, workspaceRoot, sourceRoot) {
|
|
74
|
+
return {
|
|
75
|
+
name: 'ong:assets',
|
|
76
|
+
writeBundle(bundleOpts) {
|
|
77
|
+
const outDir = bundleOpts.dir || resolve(workspaceRoot, 'dist');
|
|
78
|
+
for (const asset of assets) {
|
|
79
|
+
if (typeof asset === 'string') {
|
|
80
|
+
const src = resolve(workspaceRoot, asset);
|
|
81
|
+
if (existsSync(src)) {
|
|
82
|
+
const dest = join(outDir, asset.replace(sourceRoot + '/', ''));
|
|
83
|
+
cpSync(src, dest, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (asset?.input) {
|
|
87
|
+
const inputDir = resolve(workspaceRoot, asset.input);
|
|
88
|
+
if (existsSync(inputDir)) {
|
|
89
|
+
const outputDir = join(outDir, asset.output || '');
|
|
90
|
+
mkdirSync(outputDir, { recursive: true });
|
|
91
|
+
cpSync(inputDir, outputDir, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export interface ResolvedBuildOptions {
|
|
2
|
+
/** Absolute path to workspace root */
|
|
3
|
+
workspaceRoot: string;
|
|
4
|
+
/** Project name */
|
|
5
|
+
projectName: string;
|
|
6
|
+
/** Configuration name */
|
|
7
|
+
configName: string;
|
|
8
|
+
/** Source root relative to workspace (e.g. "src" or "apps/my-app/src") */
|
|
9
|
+
sourceRoot: string;
|
|
10
|
+
/** Absolute path to tsconfig */
|
|
11
|
+
tsconfig: string;
|
|
12
|
+
/** Absolute path to browser entry (e.g. src/main.ts) */
|
|
13
|
+
browser: string;
|
|
14
|
+
/** Absolute paths to global style files */
|
|
15
|
+
styles: string[];
|
|
16
|
+
/** Absolute paths to global script files */
|
|
17
|
+
scripts: string[];
|
|
18
|
+
/** Asset configs from angular.json */
|
|
19
|
+
assets: AssetConfig[];
|
|
20
|
+
/** File replacement pairs */
|
|
21
|
+
fileReplacements: {
|
|
22
|
+
replace: string;
|
|
23
|
+
with: string;
|
|
24
|
+
}[];
|
|
25
|
+
/** Whether to generate source maps */
|
|
26
|
+
sourceMap: boolean;
|
|
27
|
+
/** Whether to optimize (minify, tree-shake) */
|
|
28
|
+
optimization: boolean;
|
|
29
|
+
/** Output hashing mode */
|
|
30
|
+
outputHashing: 'none' | 'all' | 'media' | 'bundles';
|
|
31
|
+
/** Absolute path to output directory */
|
|
32
|
+
outputPath: string;
|
|
33
|
+
/** Base href for the application */
|
|
34
|
+
baseHref: string;
|
|
35
|
+
/** Deploy URL prefix for assets */
|
|
36
|
+
deployUrl: string;
|
|
37
|
+
/** Polyfill entries (e.g. ["zone.js"]) */
|
|
38
|
+
polyfills: string[];
|
|
39
|
+
/** Global constant replacements */
|
|
40
|
+
define: Record<string, string>;
|
|
41
|
+
/** Dependencies to treat as external */
|
|
42
|
+
externalDependencies: string[];
|
|
43
|
+
/** Preserve symlinks in module resolution */
|
|
44
|
+
preserveSymlinks: boolean;
|
|
45
|
+
/** Use human-readable chunk names */
|
|
46
|
+
namedChunks: boolean;
|
|
47
|
+
/** Cross-origin attribute for script/link tags */
|
|
48
|
+
crossOrigin: 'none' | 'anonymous' | 'use-credentials';
|
|
49
|
+
/** Sass/Less preprocessor options */
|
|
50
|
+
stylePreprocessorOptions: {
|
|
51
|
+
includePaths: string[];
|
|
52
|
+
};
|
|
53
|
+
/** Watch mode for build */
|
|
54
|
+
watch: boolean;
|
|
55
|
+
/** File-watching poll interval in ms (0 = no polling) */
|
|
56
|
+
poll: number;
|
|
57
|
+
/** Serve options */
|
|
58
|
+
serve: {
|
|
59
|
+
port?: number;
|
|
60
|
+
open?: boolean;
|
|
61
|
+
host?: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export type AssetConfig = string | {
|
|
65
|
+
glob: string;
|
|
66
|
+
input: string;
|
|
67
|
+
output?: string;
|
|
68
|
+
};
|
|
69
|
+
export interface ResolveOptions {
|
|
70
|
+
/** Project name or path */
|
|
71
|
+
project?: string;
|
|
72
|
+
/** Configuration name */
|
|
73
|
+
configuration?: string;
|
|
74
|
+
/** Command being run */
|
|
75
|
+
command: 'serve' | 'build';
|
|
76
|
+
/** Dev server port override */
|
|
77
|
+
port?: number;
|
|
78
|
+
/** Open browser on start */
|
|
79
|
+
open?: boolean;
|
|
80
|
+
/** Dev server host override */
|
|
81
|
+
host?: string;
|
|
82
|
+
/** Watch mode override for build */
|
|
83
|
+
watch?: boolean;
|
|
84
|
+
}
|
|
85
|
+
interface Target {
|
|
86
|
+
builder?: string;
|
|
87
|
+
executor?: string;
|
|
88
|
+
options?: Record<string, any>;
|
|
89
|
+
configurations?: Record<string, Record<string, any>>;
|
|
90
|
+
defaultConfiguration?: string;
|
|
91
|
+
}
|
|
92
|
+
interface Project {
|
|
93
|
+
name?: string;
|
|
94
|
+
root?: string;
|
|
95
|
+
sourceRoot?: string;
|
|
96
|
+
prefix?: string;
|
|
97
|
+
architect?: Record<string, Target>;
|
|
98
|
+
targets?: Record<string, Target>;
|
|
99
|
+
}
|
|
100
|
+
interface WorkspaceJson {
|
|
101
|
+
projects?: Record<string, Project>;
|
|
102
|
+
defaultProject?: string;
|
|
103
|
+
}
|
|
104
|
+
type WorkspaceType = 'angular' | 'nx-project';
|
|
105
|
+
interface DetectedWorkspace {
|
|
106
|
+
type: WorkspaceType;
|
|
107
|
+
root: string;
|
|
108
|
+
data: WorkspaceJson | Project;
|
|
109
|
+
projectJsonPath?: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Detect and read the workspace configuration.
|
|
113
|
+
*
|
|
114
|
+
* Supports:
|
|
115
|
+
* - angular.json (standard Angular CLI)
|
|
116
|
+
* - workspace.json (older Nx format)
|
|
117
|
+
* - project.json (per-project Nx)
|
|
118
|
+
* - Auto-detection via --project pointing to an Nx app directory
|
|
119
|
+
*/
|
|
120
|
+
export declare function detectWorkspace(cwd: string, projectHint?: string): DetectedWorkspace;
|
|
121
|
+
/**
|
|
122
|
+
* Main entry: detect workspace type and resolve all build options.
|
|
123
|
+
*/
|
|
124
|
+
export declare function resolveWorkspace(cwd: string, opts: ResolveOptions): ResolvedBuildOptions;
|
|
125
|
+
export {};
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { resolve, join, dirname, basename } from 'node:path';
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════
|
|
4
|
+
// Detection
|
|
5
|
+
// ═══════════════════════════════════════════════════════════════
|
|
6
|
+
/**
|
|
7
|
+
* Detect and read the workspace configuration.
|
|
8
|
+
*
|
|
9
|
+
* Supports:
|
|
10
|
+
* - angular.json (standard Angular CLI)
|
|
11
|
+
* - workspace.json (older Nx format)
|
|
12
|
+
* - project.json (per-project Nx)
|
|
13
|
+
* - Auto-detection via --project pointing to an Nx app directory
|
|
14
|
+
*/
|
|
15
|
+
export function detectWorkspace(cwd, projectHint) {
|
|
16
|
+
// If projectHint points to a specific project.json or directory
|
|
17
|
+
if (projectHint) {
|
|
18
|
+
const hintPath = resolve(cwd, projectHint);
|
|
19
|
+
// Direct path to project.json
|
|
20
|
+
if (hintPath.endsWith('project.json') && existsSync(hintPath)) {
|
|
21
|
+
return {
|
|
22
|
+
type: 'nx-project',
|
|
23
|
+
root: findWorkspaceRoot(dirname(hintPath)) ?? cwd,
|
|
24
|
+
data: JSON.parse(readFileSync(hintPath, 'utf-8')),
|
|
25
|
+
projectJsonPath: hintPath,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// Directory containing project.json
|
|
29
|
+
const dirProjectJson = join(hintPath, 'project.json');
|
|
30
|
+
if (existsSync(dirProjectJson)) {
|
|
31
|
+
return {
|
|
32
|
+
type: 'nx-project',
|
|
33
|
+
root: findWorkspaceRoot(hintPath) ?? cwd,
|
|
34
|
+
data: JSON.parse(readFileSync(dirProjectJson, 'utf-8')),
|
|
35
|
+
projectJsonPath: dirProjectJson,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// angular.json in cwd
|
|
40
|
+
const angularJson = resolve(cwd, 'angular.json');
|
|
41
|
+
if (existsSync(angularJson)) {
|
|
42
|
+
return {
|
|
43
|
+
type: 'angular',
|
|
44
|
+
root: cwd,
|
|
45
|
+
data: JSON.parse(readFileSync(angularJson, 'utf-8')),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// workspace.json (some Nx workspaces)
|
|
49
|
+
const workspaceJson = resolve(cwd, 'workspace.json');
|
|
50
|
+
if (existsSync(workspaceJson)) {
|
|
51
|
+
return {
|
|
52
|
+
type: 'angular',
|
|
53
|
+
root: cwd,
|
|
54
|
+
data: JSON.parse(readFileSync(workspaceJson, 'utf-8')),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// project.json in cwd (standalone Nx project or running from project dir)
|
|
58
|
+
const projectJson = resolve(cwd, 'project.json');
|
|
59
|
+
if (existsSync(projectJson)) {
|
|
60
|
+
return {
|
|
61
|
+
type: 'nx-project',
|
|
62
|
+
root: findWorkspaceRoot(cwd) ?? cwd,
|
|
63
|
+
data: JSON.parse(readFileSync(projectJson, 'utf-8')),
|
|
64
|
+
projectJsonPath: projectJson,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
throw new Error('No angular.json or project.json found.\n' +
|
|
68
|
+
' Run from an Angular/Nx workspace root, or use --project <path>.');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Walk up directories to find the workspace root (has nx.json or angular.json).
|
|
72
|
+
*/
|
|
73
|
+
function findWorkspaceRoot(from) {
|
|
74
|
+
let dir = resolve(from);
|
|
75
|
+
while (true) {
|
|
76
|
+
if (existsSync(join(dir, 'nx.json')))
|
|
77
|
+
return dir;
|
|
78
|
+
if (existsSync(join(dir, 'angular.json')))
|
|
79
|
+
return dir;
|
|
80
|
+
const parent = dirname(dir);
|
|
81
|
+
if (parent === dir)
|
|
82
|
+
return null;
|
|
83
|
+
dir = parent;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ═══════════════════════════════════════════════════════════════
|
|
87
|
+
// Resolve
|
|
88
|
+
// ═══════════════════════════════════════════════════════════════
|
|
89
|
+
/**
|
|
90
|
+
* Main entry: detect workspace type and resolve all build options.
|
|
91
|
+
*/
|
|
92
|
+
export function resolveWorkspace(cwd, opts) {
|
|
93
|
+
const ws = detectWorkspace(cwd, opts.project);
|
|
94
|
+
if (ws.type === 'nx-project') {
|
|
95
|
+
return resolveNxProject(ws, opts);
|
|
96
|
+
}
|
|
97
|
+
return resolveAngularWorkspace(ws, opts);
|
|
98
|
+
}
|
|
99
|
+
function resolveAngularWorkspace(ws, opts) {
|
|
100
|
+
const workspace = ws.data;
|
|
101
|
+
const projects = workspace.projects ?? {};
|
|
102
|
+
let projectName;
|
|
103
|
+
let project;
|
|
104
|
+
if (opts.project && projects[opts.project]) {
|
|
105
|
+
projectName = opts.project;
|
|
106
|
+
project = projects[opts.project];
|
|
107
|
+
}
|
|
108
|
+
else if (workspace.defaultProject && projects[workspace.defaultProject]) {
|
|
109
|
+
projectName = workspace.defaultProject;
|
|
110
|
+
project = projects[workspace.defaultProject];
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const entries = Object.entries(projects);
|
|
114
|
+
if (entries.length === 0)
|
|
115
|
+
throw new Error('No projects found in angular.json');
|
|
116
|
+
[projectName, project] = entries[0];
|
|
117
|
+
}
|
|
118
|
+
return resolveProjectOptions(ws.root, projectName, project, opts);
|
|
119
|
+
}
|
|
120
|
+
function resolveNxProject(ws, opts) {
|
|
121
|
+
const project = ws.data;
|
|
122
|
+
const projectName = project.name ?? basename(dirname(ws.projectJsonPath));
|
|
123
|
+
const projectDir = dirname(ws.projectJsonPath);
|
|
124
|
+
// Resolve root relative to workspace
|
|
125
|
+
const projectRoot = project.root ?? relPath(ws.root, projectDir);
|
|
126
|
+
const resolved = {
|
|
127
|
+
...project,
|
|
128
|
+
root: projectRoot,
|
|
129
|
+
sourceRoot: project.sourceRoot ?? join(projectRoot, 'src'),
|
|
130
|
+
};
|
|
131
|
+
return resolveProjectOptions(ws.root, projectName, resolved, opts);
|
|
132
|
+
}
|
|
133
|
+
function relPath(base, target) {
|
|
134
|
+
const resolved = resolve(target);
|
|
135
|
+
const baseResolved = resolve(base);
|
|
136
|
+
if (resolved.startsWith(baseResolved)) {
|
|
137
|
+
return resolved.slice(baseResolved.length + 1) || '.';
|
|
138
|
+
}
|
|
139
|
+
return resolved;
|
|
140
|
+
}
|
|
141
|
+
function resolveProjectOptions(workspaceRoot, projectName, project, opts) {
|
|
142
|
+
// Nx uses "targets", Angular CLI uses "architect"
|
|
143
|
+
const targets = project.targets ?? project.architect ?? {};
|
|
144
|
+
const buildTarget = targets['build'];
|
|
145
|
+
if (!buildTarget) {
|
|
146
|
+
throw new Error(`No "build" target found for project "${projectName}"`);
|
|
147
|
+
}
|
|
148
|
+
const serveTarget = targets['serve'];
|
|
149
|
+
// Resolve configuration name
|
|
150
|
+
let configName;
|
|
151
|
+
if (opts.configuration) {
|
|
152
|
+
configName = opts.configuration;
|
|
153
|
+
}
|
|
154
|
+
else if (opts.command === 'serve') {
|
|
155
|
+
configName = serveTarget?.defaultConfiguration ?? 'development';
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
configName = buildTarget.defaultConfiguration ?? 'production';
|
|
159
|
+
}
|
|
160
|
+
// Merge base + config overrides
|
|
161
|
+
const base = buildTarget.options ?? {};
|
|
162
|
+
const overrides = buildTarget.configurations?.[configName];
|
|
163
|
+
const merged = overrides ? { ...base, ...overrides } : { ...base };
|
|
164
|
+
// Serve target options
|
|
165
|
+
const serveBase = serveTarget?.options ?? {};
|
|
166
|
+
const serveOverrides = serveTarget?.configurations?.[configName];
|
|
167
|
+
const serveOpts = serveOverrides ? { ...serveBase, ...serveOverrides } : { ...serveBase };
|
|
168
|
+
const projectRoot = project.root ?? '';
|
|
169
|
+
const sourceRoot = project.sourceRoot ?? join(projectRoot, 'src');
|
|
170
|
+
const abs = (p) => resolve(workspaceRoot, p);
|
|
171
|
+
const tsconfig = abs(merged.tsConfig ?? join(projectRoot, 'tsconfig.app.json'));
|
|
172
|
+
const browser = abs(merged.browser ?? merged.main ?? join(sourceRoot, 'main.ts'));
|
|
173
|
+
const styles = (merged.styles ?? []).map((s) => abs(typeof s === 'string' ? s : s.input));
|
|
174
|
+
const scripts = (merged.scripts ?? []).map((s) => abs(typeof s === 'string' ? s : s.input));
|
|
175
|
+
const assets = merged.assets ?? [];
|
|
176
|
+
const fileReplacements = (merged.fileReplacements ?? []).map((fr) => ({
|
|
177
|
+
replace: abs(fr.replace),
|
|
178
|
+
with: abs(fr.with),
|
|
179
|
+
}));
|
|
180
|
+
const sourceMap = merged.sourceMap ?? (configName !== 'production');
|
|
181
|
+
const optimization = merged.optimization ?? (configName === 'production');
|
|
182
|
+
const outputHashing = merged.outputHashing ?? (configName === 'production' ? 'all' : 'none');
|
|
183
|
+
const outputPath = abs(merged.outputPath ?? join('dist', projectRoot || projectName));
|
|
184
|
+
const baseHref = merged.baseHref ?? '/';
|
|
185
|
+
const deployUrl = merged.deployUrl ?? '';
|
|
186
|
+
const crossOrigin = merged.crossOrigin ?? 'none';
|
|
187
|
+
const namedChunks = merged.namedChunks ?? false;
|
|
188
|
+
const preserveSymlinks = merged.preserveSymlinks ?? false;
|
|
189
|
+
const watch = opts.watch ?? merged.watch ?? false;
|
|
190
|
+
const poll = serveOpts.poll ?? merged.poll ?? 0;
|
|
191
|
+
const polyfills = Array.isArray(merged.polyfills)
|
|
192
|
+
? merged.polyfills
|
|
193
|
+
: merged.polyfills ? [merged.polyfills] : [];
|
|
194
|
+
const define = merged.define ?? {};
|
|
195
|
+
const externalDependencies = merged.externalDependencies ?? [];
|
|
196
|
+
const rawIncludePaths = merged.stylePreprocessorOptions?.includePaths ?? [];
|
|
197
|
+
const stylePreprocessorOptions = {
|
|
198
|
+
includePaths: rawIncludePaths.map((p) => abs(p)),
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
workspaceRoot,
|
|
202
|
+
projectName,
|
|
203
|
+
configName,
|
|
204
|
+
sourceRoot,
|
|
205
|
+
tsconfig,
|
|
206
|
+
browser,
|
|
207
|
+
styles,
|
|
208
|
+
scripts,
|
|
209
|
+
assets,
|
|
210
|
+
fileReplacements,
|
|
211
|
+
sourceMap,
|
|
212
|
+
optimization,
|
|
213
|
+
outputHashing,
|
|
214
|
+
outputPath,
|
|
215
|
+
baseHref,
|
|
216
|
+
deployUrl,
|
|
217
|
+
polyfills,
|
|
218
|
+
define,
|
|
219
|
+
externalDependencies,
|
|
220
|
+
preserveSymlinks,
|
|
221
|
+
namedChunks,
|
|
222
|
+
crossOrigin,
|
|
223
|
+
stylePreprocessorOptions,
|
|
224
|
+
watch,
|
|
225
|
+
poll,
|
|
226
|
+
serve: {
|
|
227
|
+
port: opts.port ?? serveOpts.port ?? merged.port ?? 4200,
|
|
228
|
+
open: opts.open ?? serveOpts.open ?? merged.open ?? false,
|
|
229
|
+
host: opts.host ?? serveOpts.host,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@richapps/ong",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Angular CLI powered by Vite + OXC — blazing fast drop-in replacement for ng serve/build",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"vite",
|
|
8
|
+
"oxc",
|
|
9
|
+
"cli",
|
|
10
|
+
"compiler",
|
|
11
|
+
"nx",
|
|
12
|
+
"build",
|
|
13
|
+
"dev-server"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"bin": {
|
|
18
|
+
"ong": "./bin/ong.js"
|
|
19
|
+
},
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"default": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"bin",
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc",
|
|
34
|
+
"dev": "tsc --watch",
|
|
35
|
+
"prepublishOnly": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@oxc-angular/vite": "^0.0.15"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"vite": ">=6.0.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.0.0",
|
|
45
|
+
"typescript": "~5.9.2",
|
|
46
|
+
"vite": "^8.0.0-beta.16"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/nicoss/ong"
|
|
51
|
+
}
|
|
52
|
+
}
|