@ywal123456/jskim 0.3.1 → 0.5.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 +27 -11
- package/bin/jskim.js +32 -29
- package/docs/configuration.md +26 -3
- package/docs/create-jskim.md +3 -3
- package/package.json +1 -1
- package/scripts/build.js +14 -2
- package/scripts/commands/build-command.js +113 -3
- package/scripts/commands/dev-command.js +10 -1
- package/scripts/commands/help-text.js +23 -11
- package/scripts/commands/serve-command.js +20 -4
- package/scripts/commands/serve-errors.js +30 -4
- package/scripts/commands/watch-command.js +1 -1
- package/scripts/dev.js +16 -2
- package/scripts/lib/apply-serve-cli-overrides.js +96 -0
- package/scripts/lib/assert-output-dirs-compatible.js +88 -0
- package/scripts/lib/classify-reload.js +131 -0
- package/scripts/lib/create-live-reload.js +422 -32
- package/scripts/lib/create-project-watcher.js +3 -1
- package/scripts/lib/create-watch-runtime.js +109 -16
- package/scripts/lib/open-browser.js +102 -0
- package/scripts/lib/parse-cli-args.js +216 -0
- package/scripts/lib/select-project-name.js +64 -0
- package/scripts/lib/stylesheet-reload.js +58 -0
- package/scripts/serve.js +21 -2
- package/scripts/watch.js +13 -2
package/README.md
CHANGED
|
@@ -14,14 +14,17 @@ Nunjucks を使った汎用の静的 HTML ビルド環境です。
|
|
|
14
14
|
- ファイル監視(`watch`)後の全体再ビルド
|
|
15
15
|
- ビルド結果のローカル静的サーバー(`serve`)
|
|
16
16
|
- 開発サーバー(`dev` = build + watch + serve)
|
|
17
|
-
-
|
|
17
|
+
- 成功した再ビルド後のライブリロード(SSE)
|
|
18
|
+
- 再ビルド失敗時の browser error overlay(`dev` + `liveReload`)
|
|
19
|
+
- 安全な CSS 変更時の stylesheet soft reload(`dev` + `liveReload`)
|
|
20
|
+
- CLI 便利機能(`build --all`、project 省略、`--host` / `--port`、`dev --open`)
|
|
18
21
|
- CLI binary `jskim`
|
|
19
22
|
- プロジェクト生成 CLI `create-jskim`
|
|
20
23
|
|
|
21
24
|
## 現在の非対応範囲
|
|
22
25
|
|
|
23
|
-
-
|
|
24
|
-
- HMR /
|
|
26
|
+
- ブラウザ選択 option / `serve --open`
|
|
27
|
+
- HMR / JavaScript module hot replacement
|
|
25
28
|
- JSON / YAML などの外部データファイル自動読み込み
|
|
26
29
|
- API / Mock API
|
|
27
30
|
- 増分ビルド
|
|
@@ -71,10 +74,11 @@ npx create-jskim my-project
|
|
|
71
74
|
## CLI
|
|
72
75
|
|
|
73
76
|
```bash
|
|
74
|
-
jskim build <project>
|
|
75
|
-
jskim
|
|
76
|
-
jskim
|
|
77
|
-
jskim
|
|
77
|
+
jskim build [<project>]
|
|
78
|
+
jskim build --all
|
|
79
|
+
jskim watch [<project>]
|
|
80
|
+
jskim serve [<project>] [--host <host>] [--port <port>]
|
|
81
|
+
jskim dev [<project>] [--host <host>] [--port <port>] [--open]
|
|
78
82
|
```
|
|
79
83
|
|
|
80
84
|
`package.json` の scripts 例:
|
|
@@ -95,6 +99,11 @@ jskim dev <project>
|
|
|
95
99
|
- コマンドは実行したディレクトリの `process.cwd()` をプロジェクトルートとして扱う
|
|
96
100
|
- パッケージのインストール先(`node_modules/@ywal123456/jskim`)を作業空間とはみなさない
|
|
97
101
|
- プロジェクトルートに `jskim.config.js` が必要
|
|
102
|
+
- 設定内の project が 1 件だけのとき、project 名を省略できる
|
|
103
|
+
- `build --all` は定義順に全 project を順次 build する。1 件でも失敗すれば exit code 1
|
|
104
|
+
- `--host` / `--port` は serve / dev の CLI 上書き(config より優先)。`dev` の config hot reload 中も維持される
|
|
105
|
+
- `dev --open` は listen 成功後に browser を 1 回開く。失敗しても warning のみで dev は継続する
|
|
106
|
+
- option は project の前でも後ろでもよい(例: `jskim dev --port 4000 sample`)
|
|
98
107
|
|
|
99
108
|
ヘルプ / バージョン:
|
|
100
109
|
|
|
@@ -206,7 +215,7 @@ jskim watch sample
|
|
|
206
215
|
- legacy mode: `sourceDir` + `render[].from`、`sourceDir` + `templates[]`、`sourceDir` + `copy[].from`
|
|
207
216
|
- `dist/`、`node_modules/`、`outputDir` は監視しません
|
|
208
217
|
|
|
209
|
-
`watch` / `dev` は `jskim.config.js` の変更を検知し、正常なら監視対象を更新して全体ビルドします。`dev` で `outputDir` / `serve.host` / `serve.port` / `dev.liveReload` を変えた場合は process 再起動が必要です。
|
|
218
|
+
`watch` / `dev` は `jskim.config.js` の変更を検知し、正常なら監視対象を更新して全体ビルドします。`dev` で effective な `outputDir` / `serve.host` / `serve.port` / `dev.liveReload` を変えた場合は process 再起動が必要です。CLI の `--host` / `--port` がある場合は、その上書き後の値で再起動要否を判定します。
|
|
210
219
|
|
|
211
220
|
## serve / dev
|
|
212
221
|
|
|
@@ -234,9 +243,16 @@ http://127.0.0.1:3000/
|
|
|
234
243
|
- `serve` は自動で build / watch を実行しません
|
|
235
244
|
- サーバールートは `outputDir`(例: `dist/sample`)
|
|
236
245
|
- `serve` は HTML を変換せず、ライブリロード script を注入しません
|
|
237
|
-
- `
|
|
238
|
-
- `dev`
|
|
239
|
-
-
|
|
246
|
+
- `watch` にも browser overlay / CSS soft reload はありません
|
|
247
|
+
- `dev` は `dev.liveReload: true` のときだけ browser 向け機能を有効にします
|
|
248
|
+
- 再ビルド失敗時は terminal 診断に加え、browser error overlay を表示します(成功するまで full reload / CSS reload は送りません)
|
|
249
|
+
- CSS ファイルだけが安全に変更された再ビルドでは、ページ全体ではなく stylesheet を更新します
|
|
250
|
+
- CSS 以外の変更や判定が不確実な場合は、従来どおりページ全体 reload します
|
|
251
|
+
- `dev` でも `dist` ファイルへ runtime は書き込みません
|
|
252
|
+
- `jskim serve|dev ... --host` / `--port` で待受を上書きできる(config より優先)
|
|
253
|
+
- ポート衝突時は `--port` の例と `serve.port` 変更を案内する(自動で別 port は選ばない)
|
|
254
|
+
- `jskim dev ... --open` で listen 成功後に browser を 1 回開く(失敗は warning、dev は継続)
|
|
255
|
+
- 厳格な Content Security Policy で inline script または inline style が禁止されている場合、dev の live reload・error overlay・CSS soft reload が動作しないことがあります
|
|
240
256
|
|
|
241
257
|
`/_jskim/live-reload` は `dev.liveReload: true` のときだけ使う内部予約パスです。実際の静的ファイルパスとしては使わないことを推奨します。
|
|
242
258
|
|
package/bin/jskim.js
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const path = require('node:path');
|
|
5
|
-
const { getHelpText
|
|
5
|
+
const { getHelpText } = require('../scripts/commands/help-text');
|
|
6
|
+
const { parseJskimArgv } = require('../scripts/lib/parse-cli-args');
|
|
6
7
|
const { runBuildCommand } = require('../scripts/commands/build-command');
|
|
7
8
|
const { runWatchCommand } = require('../scripts/commands/watch-command');
|
|
8
9
|
const { runServeCommand } = require('../scripts/commands/serve-command');
|
|
9
10
|
const { runDevCommand } = require('../scripts/commands/dev-command');
|
|
10
11
|
|
|
11
|
-
const COMMANDS = new Set(['build', 'watch', 'serve', 'dev']);
|
|
12
|
-
|
|
13
12
|
function readPackageVersion() {
|
|
14
13
|
// package インストール先の package.json を読む(作業空間ではない)
|
|
15
14
|
const pkg = require(path.join(__dirname, '..', 'package.json'));
|
|
@@ -28,72 +27,76 @@ function printVersion() {
|
|
|
28
27
|
* @param {string[]} argv process.argv 相当(node と script を除く)
|
|
29
28
|
*/
|
|
30
29
|
async function dispatch(argv) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
parsed = parseJskimArgv(argv);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
const message = err && err.message ? err.message : String(err);
|
|
35
|
+
console.error(message);
|
|
36
|
+
process.exitCode = 1;
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
if (
|
|
40
|
+
if (parsed.kind === 'help') {
|
|
40
41
|
printHelp();
|
|
41
42
|
process.exitCode = 0;
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
if (
|
|
46
|
+
if (parsed.kind === 'version') {
|
|
46
47
|
printVersion();
|
|
47
48
|
process.exitCode = 0;
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const projectName = argv[1];
|
|
52
|
+
const command = parsed.command;
|
|
53
|
+
const projectName = parsed.projectName;
|
|
54
|
+
const options = parsed.options;
|
|
58
55
|
const workspaceRoot = process.cwd();
|
|
59
|
-
const usageLine = `jskim ${first} <project>`;
|
|
60
|
-
const buildHint = projectName
|
|
61
|
-
? `jskim build ${projectName}`
|
|
62
|
-
: 'jskim build <project>';
|
|
63
56
|
|
|
64
|
-
if (
|
|
57
|
+
if (command === 'build') {
|
|
65
58
|
await runBuildCommand({
|
|
66
59
|
projectName,
|
|
60
|
+
all: options.all,
|
|
67
61
|
workspaceRoot,
|
|
68
|
-
usageLine,
|
|
62
|
+
usageLine: 'jskim build [<project>]',
|
|
69
63
|
});
|
|
70
64
|
return;
|
|
71
65
|
}
|
|
72
66
|
|
|
73
|
-
if (
|
|
67
|
+
if (command === 'watch') {
|
|
74
68
|
await runWatchCommand({
|
|
75
69
|
projectName,
|
|
76
70
|
workspaceRoot,
|
|
77
|
-
usageLine,
|
|
71
|
+
usageLine: 'jskim watch [<project>]',
|
|
78
72
|
});
|
|
79
73
|
return;
|
|
80
74
|
}
|
|
81
75
|
|
|
82
|
-
if (
|
|
76
|
+
if (command === 'serve') {
|
|
77
|
+
const buildHint = projectName
|
|
78
|
+
? `jskim build ${projectName}`
|
|
79
|
+
: 'jskim build [<project>]';
|
|
83
80
|
await runServeCommand({
|
|
84
81
|
projectName,
|
|
85
82
|
workspaceRoot,
|
|
86
|
-
usageLine,
|
|
83
|
+
usageLine: 'jskim serve [<project>] [--host <host>] [--port <port>]',
|
|
87
84
|
buildHint,
|
|
85
|
+
host: options.host,
|
|
86
|
+
port: options.port,
|
|
88
87
|
});
|
|
89
88
|
return;
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
if (
|
|
91
|
+
if (command === 'dev') {
|
|
93
92
|
await runDevCommand({
|
|
94
93
|
projectName,
|
|
95
94
|
workspaceRoot,
|
|
96
|
-
usageLine
|
|
95
|
+
usageLine:
|
|
96
|
+
'jskim dev [<project>] [--host <host>] [--port <port>] [--open]',
|
|
97
|
+
host: options.host,
|
|
98
|
+
port: options.port,
|
|
99
|
+
open: options.open,
|
|
97
100
|
});
|
|
98
101
|
}
|
|
99
102
|
}
|
package/docs/configuration.md
CHANGED
|
@@ -293,7 +293,23 @@ files mode では出力パスの衝突を検出します。たとえば同じ `f
|
|
|
293
293
|
| `serve.host` | 空でない `string` | `'127.0.0.1'` |
|
|
294
294
|
| `serve.port` | `1` 以上 `65535` 以下の整数 | `3000` |
|
|
295
295
|
|
|
296
|
-
`serve` は自動ビルドしません。`outputDir` が無い場合は先に `
|
|
296
|
+
`serve` は自動ビルドしません。`outputDir` が無い場合は先に `jskim build <name>` を実行してください。
|
|
297
|
+
|
|
298
|
+
CLI の `--host` / `--port` は config より優先されます。`dev` では config hot reload 後も CLI override を再適用します。
|
|
299
|
+
|
|
300
|
+
## build --all
|
|
301
|
+
|
|
302
|
+
`jskim build --all` は `Object.keys(config.projects)` の定義順に全 project を順次 build します。
|
|
303
|
+
|
|
304
|
+
- config は 1 回だけ load する
|
|
305
|
+
- project ごとの resolve / build 失敗があっても、可能な限り次の project を続ける
|
|
306
|
+
- 1 件でも失敗すれば最終 exit code は 1
|
|
307
|
+
- 同一または入れ子の `outputDir` は、どの build も始める前にエラーで中断する
|
|
308
|
+
- `jskim build all` は名前が `all` の project 1 件を build する(`--all` とは別)
|
|
309
|
+
|
|
310
|
+
## project 名の省略
|
|
311
|
+
|
|
312
|
+
設定内の project がちょうど 1 件のとき、`build` / `watch` / `serve` / `dev` で project 名を省略できます。0 件または 2 件以上では明示指定が必要です(`build --all` を除く)。
|
|
297
313
|
|
|
298
314
|
## dev.liveReload
|
|
299
315
|
|
|
@@ -309,16 +325,21 @@ files mode では出力パスの衝突を検出します。たとえば同じ `f
|
|
|
309
325
|
|
|
310
326
|
- `GET /_jskim/live-reload` で SSE を提供
|
|
311
327
|
- HTML レスポンスにだけ client script を一時注入(`dist` には書き込まない)
|
|
312
|
-
- 成功した再ビルドのあとだけ
|
|
328
|
+
- 成功した再ビルドのあとだけ browser 更新を送信(通常はページ全体 reload)
|
|
329
|
+
- 再ビルド失敗時は browser error overlay を表示(成功するまで reload / CSS 更新は送らない)
|
|
330
|
+
- CSS ファイルだけが安全に変更された場合は、ページ全体ではなく stylesheet を更新
|
|
313
331
|
|
|
314
332
|
`false` のとき:
|
|
315
333
|
|
|
316
334
|
- SSE endpoint は提供しない(404)
|
|
317
335
|
- HTML への script 注入なし
|
|
336
|
+
- error overlay / CSS soft reload も無効
|
|
318
337
|
- build + watch + serve 自体は動作
|
|
319
338
|
|
|
320
339
|
`/_jskim/live-reload` は内部予約パスです。プロジェクトの静的ファイルとしては使わないことを推奨します。
|
|
321
340
|
|
|
341
|
+
厳格な Content Security Policy で inline script または inline style が禁止されている場合、dev の live reload・error overlay・CSS soft reload が動作しないことがあります。`watch` と `serve` にはこれらの browser 機能はありません。
|
|
342
|
+
|
|
322
343
|
## config hot reload
|
|
323
344
|
|
|
324
345
|
`watch` と `dev` はワークスペースルートの `jskim.config.js` を監視します。
|
|
@@ -330,13 +351,15 @@ files mode では出力パスの衝突を検出します。たとえば同じ `f
|
|
|
330
351
|
| `watch` | config 変更を hot apply。`outputDir` 変更も可。以前の outputDir は自動削除しない |
|
|
331
352
|
| `dev` | build / watch 関連設定を hot apply。一部 runtime 設定は再起動が必要 |
|
|
332
353
|
|
|
333
|
-
`dev`
|
|
354
|
+
`dev` では次の **effective** 値が変わった candidate config は適用しません。
|
|
334
355
|
|
|
335
356
|
- `outputDir`
|
|
336
357
|
- `serve.host`
|
|
337
358
|
- `serve.port`
|
|
338
359
|
- `dev.liveReload`
|
|
339
360
|
|
|
361
|
+
CLI の `--host` / `--port` がある場合は、上書き適用後の値で比較します。そのため CLI で port を固定しているあいだに config の `serve.port` だけが変わっても、effective が同じなら再起動警告は出ません。
|
|
362
|
+
|
|
340
363
|
理由: server bind と serve root を安全に切り替えるには process 再起動が必要で、部分適用すると build output と serve root がずれるためです。
|
|
341
364
|
|
|
342
365
|
## パス基準のまとめ
|
package/docs/create-jskim.md
CHANGED
|
@@ -54,12 +54,12 @@ project/
|
|
|
54
54
|
|
|
55
55
|
`jskim.config.js` は `files: [{ from: 'pages', to: '' }]` を使います。`.njk` は末尾の `.njk` だけを外してレンダリングし、画像などはそのままコピーします。
|
|
56
56
|
|
|
57
|
-
`package.json` の scripts は bin 名 `jskim` を使います(package name ではありません)。既定の engine dependency は `@ywal123456/jskim`(`^0.
|
|
57
|
+
`package.json` の scripts は bin 名 `jskim` を使います(package name ではありません)。既定の engine dependency は `@ywal123456/jskim`(`^0.5.0`)です。
|
|
58
58
|
|
|
59
59
|
```json
|
|
60
60
|
{
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@ywal123456/jskim": "^0.
|
|
62
|
+
"@ywal123456/jskim": "^0.5.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"build": "jskim build sample",
|
|
@@ -85,7 +85,7 @@ create package の `package.json` に `jskimEngine` metadata を持ち、生成
|
|
|
85
85
|
{
|
|
86
86
|
"jskimEngine": {
|
|
87
87
|
"packageName": "@ywal123456/jskim",
|
|
88
|
-
"version": "^0.
|
|
88
|
+
"version": "^0.5.0"
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
```
|
package/package.json
CHANGED
package/scripts/build.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { parseCommandArgv } = require('./lib/parse-cli-args');
|
|
3
4
|
const { runBuildCommand } = require('./commands/build-command');
|
|
4
5
|
|
|
6
|
+
let parsed;
|
|
7
|
+
try {
|
|
8
|
+
parsed = parseCommandArgv('build', process.argv.slice(2));
|
|
9
|
+
} catch (err) {
|
|
10
|
+
const message = err && err.message ? err.message : String(err);
|
|
11
|
+
console.error(message);
|
|
12
|
+
process.exitCode = 1;
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
runBuildCommand({
|
|
6
|
-
projectName:
|
|
17
|
+
projectName: parsed.projectName,
|
|
18
|
+
all: parsed.options.all,
|
|
7
19
|
workspaceRoot: process.cwd(),
|
|
8
|
-
usageLine: '
|
|
20
|
+
usageLine: 'jskim build [<project>]',
|
|
9
21
|
}).catch((err) => {
|
|
10
22
|
const message = err && err.message ? err.message : String(err);
|
|
11
23
|
console.error(message);
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { loadConfig } = require('../lib/load-config');
|
|
4
|
+
const { resolveProject } = require('../lib/resolve-project');
|
|
5
|
+
const { buildProject, runBuild } = require('../lib/build-project');
|
|
6
|
+
const { listProjectNames, selectProjectName } = require('../lib/select-project-name');
|
|
7
|
+
const {
|
|
8
|
+
assertCompatibleOutputDirs,
|
|
9
|
+
} = require('../lib/assert-output-dirs-compatible');
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
12
|
* build コマンドを実行します。
|
|
7
13
|
* @param {object} options
|
|
8
14
|
* @param {string|undefined} options.projectName
|
|
15
|
+
* @param {boolean} [options.all]
|
|
9
16
|
* @param {string} [options.workspaceRoot]
|
|
10
17
|
* @param {string} [options.usageLine]
|
|
11
18
|
* @returns {Promise<object>}
|
|
@@ -13,9 +20,24 @@ const { buildProject } = require('../lib/build-project');
|
|
|
13
20
|
async function runBuildCommand(options = {}) {
|
|
14
21
|
const workspaceRoot = options.workspaceRoot || process.cwd();
|
|
15
22
|
const usageLine =
|
|
16
|
-
options.usageLine || '
|
|
23
|
+
options.usageLine || 'jskim build [<project>]';
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
if (options.all) {
|
|
26
|
+
return runBuildAllProjects({
|
|
27
|
+
workspaceRoot,
|
|
28
|
+
usageLine,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { config } = loadConfig(workspaceRoot);
|
|
33
|
+
const projectName = selectProjectName({
|
|
34
|
+
config,
|
|
35
|
+
projectName: options.projectName,
|
|
36
|
+
commandName: 'build',
|
|
37
|
+
usageLine,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return buildProject(projectName, {
|
|
19
41
|
workspaceRoot,
|
|
20
42
|
commandName: 'build',
|
|
21
43
|
usageLine,
|
|
@@ -24,6 +46,94 @@ async function runBuildCommand(options = {}) {
|
|
|
24
46
|
});
|
|
25
47
|
}
|
|
26
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @param {object} options
|
|
51
|
+
* @returns {Promise<object>}
|
|
52
|
+
*/
|
|
53
|
+
async function runBuildAllProjects({ workspaceRoot, usageLine }) {
|
|
54
|
+
const { config } = loadConfig(workspaceRoot);
|
|
55
|
+
const names = listProjectNames(config);
|
|
56
|
+
|
|
57
|
+
if (names.length === 0) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`[JSKim] 設定にprojectがありません。\n` +
|
|
60
|
+
`jskim.config.js の projects に1件以上定義してください。\n` +
|
|
61
|
+
`使用方法: jskim build --all`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** @type {object[]} */
|
|
66
|
+
const resolved = [];
|
|
67
|
+
/** @type {Array<{ name: string, stage: string, message: string }>} */
|
|
68
|
+
const failures = [];
|
|
69
|
+
/** @type {string[]} */
|
|
70
|
+
const successes = [];
|
|
71
|
+
|
|
72
|
+
for (const name of names) {
|
|
73
|
+
try {
|
|
74
|
+
const project = resolveProject({
|
|
75
|
+
config,
|
|
76
|
+
workspaceRoot,
|
|
77
|
+
projectName: name,
|
|
78
|
+
commandName: 'build',
|
|
79
|
+
usageLine,
|
|
80
|
+
});
|
|
81
|
+
resolved.push(project);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
const message = err && err.message ? err.message : String(err);
|
|
84
|
+
failures.push({ name, stage: 'resolve', message });
|
|
85
|
+
console.error(message);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (resolved.length > 0) {
|
|
90
|
+
assertCompatibleOutputDirs(resolved);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (const project of resolved) {
|
|
94
|
+
console.log(`[JSKim] project "${project.name}" のbuildを開始します`);
|
|
95
|
+
try {
|
|
96
|
+
await runBuild(project, {
|
|
97
|
+
logTitle: 'ビルドが完了しました',
|
|
98
|
+
includeOutput: true,
|
|
99
|
+
});
|
|
100
|
+
successes.push(project.name);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
const message = err && err.message ? err.message : String(err);
|
|
103
|
+
failures.push({ name: project.name, stage: 'build', message });
|
|
104
|
+
console.error(message);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const total = names.length;
|
|
109
|
+
const failCount = failures.length;
|
|
110
|
+
const successCount = successes.length;
|
|
111
|
+
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(
|
|
114
|
+
`[JSKim] ${total}件中${successCount}件のprojectのbuildが完了しました`
|
|
115
|
+
);
|
|
116
|
+
if (failCount > 0) {
|
|
117
|
+
console.log(`[JSKim] 失敗: ${failCount}件`);
|
|
118
|
+
for (const item of failures) {
|
|
119
|
+
console.log(`- ${item.name} (${item.stage})`);
|
|
120
|
+
}
|
|
121
|
+
const error = new Error(
|
|
122
|
+
`[JSKim] build --all が失敗しました(成功 ${successCount} / 失敗 ${failCount} / 全 ${total})。`
|
|
123
|
+
);
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
total,
|
|
129
|
+
successCount,
|
|
130
|
+
failCount,
|
|
131
|
+
successes,
|
|
132
|
+
failures,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
27
136
|
module.exports = {
|
|
28
137
|
runBuildCommand,
|
|
138
|
+
runBuildAllProjects,
|
|
29
139
|
};
|
|
@@ -9,12 +9,16 @@ const { registerShutdown } = require('./register-shutdown');
|
|
|
9
9
|
* @param {string|undefined} options.projectName
|
|
10
10
|
* @param {string} [options.workspaceRoot]
|
|
11
11
|
* @param {string} [options.usageLine]
|
|
12
|
+
* @param {string} [options.host]
|
|
13
|
+
* @param {string|number} [options.port]
|
|
14
|
+
* @param {boolean} [options.open]
|
|
12
15
|
* @returns {Promise<void>}
|
|
13
16
|
*/
|
|
14
17
|
async function runDevCommand(options = {}) {
|
|
15
18
|
const workspaceRoot = options.workspaceRoot || process.cwd();
|
|
16
19
|
const usageLine =
|
|
17
|
-
options.usageLine ||
|
|
20
|
+
options.usageLine ||
|
|
21
|
+
'jskim dev [<project>] [--host <host>] [--port <port>] [--open]';
|
|
18
22
|
|
|
19
23
|
const runtime = createWatchRuntime({
|
|
20
24
|
mode: 'dev',
|
|
@@ -22,6 +26,11 @@ async function runDevCommand(options = {}) {
|
|
|
22
26
|
projectName: options.projectName,
|
|
23
27
|
commandName: 'dev',
|
|
24
28
|
usageLine,
|
|
29
|
+
cliOverrides: {
|
|
30
|
+
host: options.host,
|
|
31
|
+
port: options.port,
|
|
32
|
+
open: Boolean(options.open),
|
|
33
|
+
},
|
|
25
34
|
});
|
|
26
35
|
|
|
27
36
|
let stopping = false;
|
|
@@ -9,17 +9,28 @@ function getHelpText() {
|
|
|
9
9
|
'JSKim - Nunjucksを使用した静的HTMLビルド環境',
|
|
10
10
|
'',
|
|
11
11
|
'使用方法:',
|
|
12
|
-
' jskim
|
|
12
|
+
' jskim build [<project>]',
|
|
13
|
+
' jskim build --all',
|
|
14
|
+
' jskim watch [<project>]',
|
|
15
|
+
' jskim serve [<project>] [--host <host>] [--port <port>]',
|
|
16
|
+
' jskim dev [<project>] [--host <host>] [--port <port>] [--open]',
|
|
13
17
|
'',
|
|
14
18
|
'コマンド:',
|
|
15
|
-
' build
|
|
16
|
-
' watch
|
|
17
|
-
' serve
|
|
18
|
-
' dev
|
|
19
|
+
' build 静的ファイルをビルドします。',
|
|
20
|
+
' watch ファイルの変更を監視して再ビルドします。',
|
|
21
|
+
' serve ビルド済みのファイルを配信します。',
|
|
22
|
+
' dev ビルド・監視・サーバー・ライブリロードを起動します。',
|
|
19
23
|
'',
|
|
20
24
|
'オプション:',
|
|
21
|
-
'
|
|
22
|
-
'
|
|
25
|
+
' --all 設定内の全projectを順にbuildします(buildのみ)。',
|
|
26
|
+
' --host <host> serve / dev の待受ホストを上書きします。',
|
|
27
|
+
' --port <port> serve / dev の待受ポートを上書きします。',
|
|
28
|
+
' --open listen成功後にbrowserを1回開きます(devのみ)。',
|
|
29
|
+
' -h, --help ヘルプを表示します。',
|
|
30
|
+
' -v, --version バージョンを表示します。',
|
|
31
|
+
'',
|
|
32
|
+
'補足:',
|
|
33
|
+
' projectを省略できるのは、設定内のprojectが1件だけの場合です。',
|
|
23
34
|
].join('\n');
|
|
24
35
|
}
|
|
25
36
|
|
|
@@ -33,10 +44,11 @@ function getUnknownCommandText(command) {
|
|
|
33
44
|
`[JSKim] 不明なコマンドです: ${command}`,
|
|
34
45
|
'',
|
|
35
46
|
'使用できるコマンド:',
|
|
36
|
-
' build <project>',
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
47
|
+
' build [<project>]',
|
|
48
|
+
' build --all',
|
|
49
|
+
' watch [<project>]',
|
|
50
|
+
' serve [<project>] [--host <host>] [--port <port>]',
|
|
51
|
+
' dev [<project>] [--host <host>] [--port <port>] [--open]',
|
|
40
52
|
].join('\n');
|
|
41
53
|
}
|
|
42
54
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { loadConfig } = require('../lib/load-config');
|
|
4
4
|
const { resolveProject } = require('../lib/resolve-project');
|
|
5
|
+
const { selectProjectName } = require('../lib/select-project-name');
|
|
6
|
+
const { applyServeCliOverrides } = require('../lib/apply-serve-cli-overrides');
|
|
5
7
|
const { createStaticServer } = require('../lib/create-static-server');
|
|
6
8
|
const { registerShutdown } = require('./register-shutdown');
|
|
7
9
|
const { toDisplayPath } = require('./path-display');
|
|
@@ -14,24 +16,37 @@ const { assertOutputDirReady, formatListenError } = require('./serve-errors');
|
|
|
14
16
|
* @param {string} [options.workspaceRoot]
|
|
15
17
|
* @param {string} [options.usageLine]
|
|
16
18
|
* @param {string} [options.buildHint]
|
|
19
|
+
* @param {string} [options.host]
|
|
20
|
+
* @param {string|number} [options.port]
|
|
17
21
|
* @returns {Promise<void>}
|
|
18
22
|
*/
|
|
19
23
|
async function runServeCommand(options = {}) {
|
|
20
24
|
const workspaceRoot = options.workspaceRoot || process.cwd();
|
|
21
25
|
const usageLine =
|
|
22
|
-
options.usageLine || '
|
|
26
|
+
options.usageLine || 'jskim serve [<project>] [--host <host>] [--port <port>]';
|
|
23
27
|
|
|
24
28
|
const { config } = loadConfig(workspaceRoot);
|
|
25
|
-
const
|
|
29
|
+
const projectName = selectProjectName({
|
|
26
30
|
config,
|
|
27
|
-
workspaceRoot,
|
|
28
31
|
projectName: options.projectName,
|
|
29
32
|
commandName: 'serve',
|
|
30
33
|
usageLine,
|
|
31
34
|
});
|
|
32
35
|
|
|
36
|
+
let project = resolveProject({
|
|
37
|
+
config,
|
|
38
|
+
workspaceRoot,
|
|
39
|
+
projectName,
|
|
40
|
+
commandName: 'serve',
|
|
41
|
+
usageLine,
|
|
42
|
+
});
|
|
43
|
+
project = applyServeCliOverrides(project, {
|
|
44
|
+
host: options.host,
|
|
45
|
+
port: options.port,
|
|
46
|
+
});
|
|
47
|
+
|
|
33
48
|
const buildHint =
|
|
34
|
-
options.buildHint || `
|
|
49
|
+
options.buildHint || `jskim build ${project.name}`;
|
|
35
50
|
assertOutputDirReady(project, { buildHint });
|
|
36
51
|
|
|
37
52
|
const host = project.serve.host.trim();
|
|
@@ -53,6 +68,7 @@ async function runServeCommand(options = {}) {
|
|
|
53
68
|
host,
|
|
54
69
|
port,
|
|
55
70
|
kind: '静的',
|
|
71
|
+
commandName: 'serve',
|
|
56
72
|
});
|
|
57
73
|
}
|
|
58
74
|
|
|
@@ -10,7 +10,7 @@ const fs = require('node:fs');
|
|
|
10
10
|
*/
|
|
11
11
|
function assertOutputDirReady(project, options = {}) {
|
|
12
12
|
const { name, outputDir, outputDirConfig } = project;
|
|
13
|
-
const buildHint = options.buildHint || `
|
|
13
|
+
const buildHint = options.buildHint || `jskim build ${name}`;
|
|
14
14
|
|
|
15
15
|
if (!outputDir || String(outputDir).trim() === '') {
|
|
16
16
|
throw new Error(
|
|
@@ -44,15 +44,32 @@ function assertOutputDirReady(project, options = {}) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* @param {Error} err
|
|
49
|
+
* @param {object} options
|
|
50
|
+
* @param {string} options.projectName
|
|
51
|
+
* @param {string} options.host
|
|
52
|
+
* @param {number} options.port
|
|
53
|
+
* @param {string} [options.kind]
|
|
54
|
+
* @param {'serve'|'dev'|string} [options.commandName]
|
|
55
|
+
*/
|
|
56
|
+
function formatListenError(
|
|
57
|
+
err,
|
|
58
|
+
{ projectName, host, port, kind = '静的', commandName }
|
|
59
|
+
) {
|
|
48
60
|
const code = err && err.code;
|
|
61
|
+
const command = commandName === 'dev' ? 'dev' : 'serve';
|
|
49
62
|
|
|
50
63
|
if (code === 'EADDRINUSE') {
|
|
64
|
+
const examplePort = suggestAlternatePort(port);
|
|
51
65
|
return new Error(
|
|
52
66
|
`[JSKim] ポート ${port} はすでに使用されています。\n` +
|
|
53
67
|
`プロジェクト: ${projectName}\n` +
|
|
54
|
-
`ホスト: ${host}\n
|
|
55
|
-
|
|
68
|
+
`ホスト: ${host}\n` +
|
|
69
|
+
`ポート: ${port}\n\n` +
|
|
70
|
+
`別のportを指定する例:\n` +
|
|
71
|
+
`jskim ${command} ${projectName} --port ${examplePort}\n\n` +
|
|
72
|
+
`または jskim.config.js の serve.port を変更してください。`
|
|
56
73
|
);
|
|
57
74
|
}
|
|
58
75
|
|
|
@@ -76,7 +93,16 @@ function formatListenError(err, { projectName, host, port, kind = '静的' }) {
|
|
|
76
93
|
);
|
|
77
94
|
}
|
|
78
95
|
|
|
96
|
+
function suggestAlternatePort(port) {
|
|
97
|
+
const n = Number(port);
|
|
98
|
+
if (Number.isInteger(n) && n >= 1 && n < 65535) {
|
|
99
|
+
return n + 1;
|
|
100
|
+
}
|
|
101
|
+
return 3001;
|
|
102
|
+
}
|
|
103
|
+
|
|
79
104
|
module.exports = {
|
|
80
105
|
assertOutputDirReady,
|
|
81
106
|
formatListenError,
|
|
107
|
+
suggestAlternatePort,
|
|
82
108
|
};
|