@ywal123456/jskim 0.4.0 → 0.5.1
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 +19 -8
- package/bin/jskim.js +32 -29
- package/docs/configuration.md +20 -2
- package/docs/create-jskim.md +20 -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/create-watch-runtime.js +70 -9
- 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/serve.js +21 -2
- package/scripts/watch.js +13 -2
package/README.md
CHANGED
|
@@ -17,12 +17,13 @@ Nunjucks を使った汎用の静的 HTML ビルド環境です。
|
|
|
17
17
|
- 成功した再ビルド後のライブリロード(SSE)
|
|
18
18
|
- 再ビルド失敗時の browser error overlay(`dev` + `liveReload`)
|
|
19
19
|
- 安全な CSS 変更時の stylesheet soft reload(`dev` + `liveReload`)
|
|
20
|
+
- CLI 便利機能(`build --all`、project 省略、`--host` / `--port`、`dev --open`)
|
|
20
21
|
- CLI binary `jskim`
|
|
21
22
|
- プロジェクト生成 CLI `create-jskim`
|
|
22
23
|
|
|
23
24
|
## 現在の非対応範囲
|
|
24
25
|
|
|
25
|
-
-
|
|
26
|
+
- ブラウザ選択 option / `serve --open`
|
|
26
27
|
- HMR / JavaScript module hot replacement
|
|
27
28
|
- JSON / YAML などの外部データファイル自動読み込み
|
|
28
29
|
- API / Mock API
|
|
@@ -60,6 +61,8 @@ npm install --save-dev @ywal123456/jskim
|
|
|
60
61
|
|
|
61
62
|
```bash
|
|
62
63
|
npm create jskim@latest
|
|
64
|
+
pnpm create jskim
|
|
65
|
+
yarn create jskim
|
|
63
66
|
```
|
|
64
67
|
|
|
65
68
|
代替:
|
|
@@ -68,15 +71,16 @@ npm create jskim@latest
|
|
|
68
71
|
npx create-jskim my-project
|
|
69
72
|
```
|
|
70
73
|
|
|
71
|
-
生成器は自動で `npm install` / `git init`
|
|
74
|
+
生成器は自動で `npm install` / `git init` を実行しません。空ではない既存ディレクトリも上書きしません。完了案内は実行した package manager に合わせた install / dev コマンドと、既定の開発 URL(`http://127.0.0.1:3000/`)を表示します。
|
|
72
75
|
|
|
73
76
|
## CLI
|
|
74
77
|
|
|
75
78
|
```bash
|
|
76
|
-
jskim build <project>
|
|
77
|
-
jskim
|
|
78
|
-
jskim
|
|
79
|
-
jskim
|
|
79
|
+
jskim build [<project>]
|
|
80
|
+
jskim build --all
|
|
81
|
+
jskim watch [<project>]
|
|
82
|
+
jskim serve [<project>] [--host <host>] [--port <port>]
|
|
83
|
+
jskim dev [<project>] [--host <host>] [--port <port>] [--open]
|
|
80
84
|
```
|
|
81
85
|
|
|
82
86
|
`package.json` の scripts 例:
|
|
@@ -97,6 +101,11 @@ jskim dev <project>
|
|
|
97
101
|
- コマンドは実行したディレクトリの `process.cwd()` をプロジェクトルートとして扱う
|
|
98
102
|
- パッケージのインストール先(`node_modules/@ywal123456/jskim`)を作業空間とはみなさない
|
|
99
103
|
- プロジェクトルートに `jskim.config.js` が必要
|
|
104
|
+
- 設定内の project が 1 件だけのとき、project 名を省略できる
|
|
105
|
+
- `build --all` は定義順に全 project を順次 build する。1 件でも失敗すれば exit code 1
|
|
106
|
+
- `--host` / `--port` は serve / dev の CLI 上書き(config より優先)。`dev` の config hot reload 中も維持される
|
|
107
|
+
- `dev --open` は listen 成功後に browser を 1 回開く。失敗しても warning のみで dev は継続する
|
|
108
|
+
- option は project の前でも後ろでもよい(例: `jskim dev --port 4000 sample`)
|
|
100
109
|
|
|
101
110
|
ヘルプ / バージョン:
|
|
102
111
|
|
|
@@ -208,7 +217,7 @@ jskim watch sample
|
|
|
208
217
|
- legacy mode: `sourceDir` + `render[].from`、`sourceDir` + `templates[]`、`sourceDir` + `copy[].from`
|
|
209
218
|
- `dist/`、`node_modules/`、`outputDir` は監視しません
|
|
210
219
|
|
|
211
|
-
`watch` / `dev` は `jskim.config.js` の変更を検知し、正常なら監視対象を更新して全体ビルドします。`dev` で `outputDir` / `serve.host` / `serve.port` / `dev.liveReload` を変えた場合は process 再起動が必要です。
|
|
220
|
+
`watch` / `dev` は `jskim.config.js` の変更を検知し、正常なら監視対象を更新して全体ビルドします。`dev` で effective な `outputDir` / `serve.host` / `serve.port` / `dev.liveReload` を変えた場合は process 再起動が必要です。CLI の `--host` / `--port` がある場合は、その上書き後の値で再起動要否を判定します。
|
|
212
221
|
|
|
213
222
|
## serve / dev
|
|
214
223
|
|
|
@@ -242,7 +251,9 @@ http://127.0.0.1:3000/
|
|
|
242
251
|
- CSS ファイルだけが安全に変更された再ビルドでは、ページ全体ではなく stylesheet を更新します
|
|
243
252
|
- CSS 以外の変更や判定が不確実な場合は、従来どおりページ全体 reload します
|
|
244
253
|
- `dev` でも `dist` ファイルへ runtime は書き込みません
|
|
245
|
-
-
|
|
254
|
+
- `jskim serve|dev ... --host` / `--port` で待受を上書きできる(config より優先)
|
|
255
|
+
- ポート衝突時は `--port` の例と `serve.port` 変更を案内する(自動で別 port は選ばない)
|
|
256
|
+
- `jskim dev ... --open` で listen 成功後に browser を 1 回開く(失敗は warning、dev は継続)
|
|
246
257
|
- 厳格な Content Security Policy で inline script または inline style が禁止されている場合、dev の live reload・error overlay・CSS soft reload が動作しないことがあります
|
|
247
258
|
|
|
248
259
|
`/_jskim/live-reload` は `dev.liveReload: true` のときだけ使う内部予約パスです。実際の静的ファイルパスとしては使わないことを推奨します。
|
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
|
|
|
@@ -335,13 +351,15 @@ files mode では出力パスの衝突を検出します。たとえば同じ `f
|
|
|
335
351
|
| `watch` | config 変更を hot apply。`outputDir` 変更も可。以前の outputDir は自動削除しない |
|
|
336
352
|
| `dev` | build / watch 関連設定を hot apply。一部 runtime 設定は再起動が必要 |
|
|
337
353
|
|
|
338
|
-
`dev`
|
|
354
|
+
`dev` では次の **effective** 値が変わった candidate config は適用しません。
|
|
339
355
|
|
|
340
356
|
- `outputDir`
|
|
341
357
|
- `serve.host`
|
|
342
358
|
- `serve.port`
|
|
343
359
|
- `dev.liveReload`
|
|
344
360
|
|
|
361
|
+
CLI の `--host` / `--port` がある場合は、上書き適用後の値で比較します。そのため CLI で port を固定しているあいだに config の `serve.port` だけが変わっても、effective が同じなら再起動警告は出ません。
|
|
362
|
+
|
|
345
363
|
理由: server bind と serve root を安全に切り替えるには process 再起動が必要で、部分適用すると build output と serve root がずれるためです。
|
|
346
364
|
|
|
347
365
|
## パス基準のまとめ
|
package/docs/create-jskim.md
CHANGED
|
@@ -24,9 +24,26 @@
|
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
npm create jskim@latest
|
|
27
|
+
pnpm create jskim
|
|
28
|
+
yarn create jskim
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
代替:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
27
34
|
npx create-jskim my-project
|
|
28
35
|
```
|
|
29
36
|
|
|
37
|
+
生成完了後の案内は、実行した package manager に合わせて install / dev コマンドを表示します。検知できない実行方法では npm コマンドが表示されることがあります。
|
|
38
|
+
|
|
39
|
+
生成器は dependency を自動インストールしません。案内に従って手動で install してください。
|
|
40
|
+
|
|
41
|
+
既定の開発サーバー URL:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
http://127.0.0.1:3000/
|
|
45
|
+
```
|
|
46
|
+
|
|
30
47
|
## 生成結果
|
|
31
48
|
|
|
32
49
|
```text
|
|
@@ -54,12 +71,12 @@ project/
|
|
|
54
71
|
|
|
55
72
|
`jskim.config.js` は `files: [{ from: 'pages', to: '' }]` を使います。`.njk` は末尾の `.njk` だけを外してレンダリングし、画像などはそのままコピーします。
|
|
56
73
|
|
|
57
|
-
`package.json` の scripts は bin 名 `jskim` を使います(package name ではありません)。既定の engine dependency は `@ywal123456/jskim`(`^0.
|
|
74
|
+
`package.json` の scripts は bin 名 `jskim` を使います(package name ではありません)。既定の engine dependency は `@ywal123456/jskim`(`^0.5.1`)です。
|
|
58
75
|
|
|
59
76
|
```json
|
|
60
77
|
{
|
|
61
78
|
"devDependencies": {
|
|
62
|
-
"@ywal123456/jskim": "^0.
|
|
79
|
+
"@ywal123456/jskim": "^0.5.1"
|
|
63
80
|
},
|
|
64
81
|
"scripts": {
|
|
65
82
|
"build": "jskim build sample",
|
|
@@ -85,7 +102,7 @@ create package の `package.json` に `jskimEngine` metadata を持ち、生成
|
|
|
85
102
|
{
|
|
86
103
|
"jskimEngine": {
|
|
87
104
|
"packageName": "@ywal123456/jskim",
|
|
88
|
-
"version": "^0.
|
|
105
|
+
"version": "^0.5.1"
|
|
89
106
|
}
|
|
90
107
|
}
|
|
91
108
|
```
|
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
|
};
|