@ywal123456/jskim 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/LICENSE +21 -0
- package/README.md +336 -0
- package/bin/jskim.js +105 -0
- package/docs/configuration.md +322 -0
- package/docs/create-jskim.md +80 -0
- package/docs/publishing.md +134 -0
- package/package.json +57 -0
- package/scripts/build.js +13 -0
- package/scripts/commands/build-command.js +29 -0
- package/scripts/commands/dev-command.js +164 -0
- package/scripts/commands/help-text.js +46 -0
- package/scripts/commands/path-display.js +21 -0
- package/scripts/commands/register-shutdown.js +32 -0
- package/scripts/commands/serve-command.js +88 -0
- package/scripts/commands/serve-errors.js +82 -0
- package/scripts/commands/watch-command.js +71 -0
- package/scripts/dev.js +13 -0
- package/scripts/lib/build-project.js +106 -0
- package/scripts/lib/clean-output.js +119 -0
- package/scripts/lib/copy-files.js +116 -0
- package/scripts/lib/create-live-reload.js +201 -0
- package/scripts/lib/create-nunjucks-env.js +61 -0
- package/scripts/lib/create-project-watcher.js +272 -0
- package/scripts/lib/create-static-server.js +351 -0
- package/scripts/lib/load-config.js +64 -0
- package/scripts/lib/merge-config.js +130 -0
- package/scripts/lib/render-pages.js +121 -0
- package/scripts/lib/resolve-project.js +198 -0
- package/scripts/lib/resolve-watch-paths.js +134 -0
- package/scripts/serve.js +13 -0
- package/scripts/watch.js +13 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { loadConfig } = require('../lib/load-config');
|
|
4
|
+
const { resolveProject } = require('../lib/resolve-project');
|
|
5
|
+
const { createProjectWatcher } = require('../lib/create-project-watcher');
|
|
6
|
+
const { createStaticServer } = require('../lib/create-static-server');
|
|
7
|
+
const { createLiveReload } = require('../lib/create-live-reload');
|
|
8
|
+
const { registerShutdown } = require('./register-shutdown');
|
|
9
|
+
const { toDisplayPath } = require('./path-display');
|
|
10
|
+
const { formatListenError } = require('./serve-errors');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* dev コマンドを実行します。
|
|
14
|
+
* @param {object} options
|
|
15
|
+
* @param {string|undefined} options.projectName
|
|
16
|
+
* @param {string} [options.workspaceRoot]
|
|
17
|
+
* @param {string} [options.usageLine]
|
|
18
|
+
* @returns {Promise<void>}
|
|
19
|
+
*/
|
|
20
|
+
async function runDevCommand(options = {}) {
|
|
21
|
+
const workspaceRoot = options.workspaceRoot || process.cwd();
|
|
22
|
+
const usageLine =
|
|
23
|
+
options.usageLine || 'npm run dev -- <project-name>';
|
|
24
|
+
|
|
25
|
+
const { config } = loadConfig(workspaceRoot);
|
|
26
|
+
const project = resolveProject({
|
|
27
|
+
config,
|
|
28
|
+
workspaceRoot,
|
|
29
|
+
projectName: options.projectName,
|
|
30
|
+
commandName: 'dev',
|
|
31
|
+
usageLine,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const host = project.serve.host.trim();
|
|
35
|
+
const port = project.serve.port;
|
|
36
|
+
const liveReloadEnabled = project.dev.liveReload;
|
|
37
|
+
const outputDisplay = toDisplayPath(project.outputDir, workspaceRoot);
|
|
38
|
+
|
|
39
|
+
const liveReload = createLiveReload({
|
|
40
|
+
projectName: project.name,
|
|
41
|
+
enabled: liveReloadEnabled,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const staticServer = createStaticServer({
|
|
45
|
+
rootDir: project.outputDir,
|
|
46
|
+
host,
|
|
47
|
+
port,
|
|
48
|
+
projectName: project.name,
|
|
49
|
+
handleInternalRequest: (req, res, meta) =>
|
|
50
|
+
liveReload.handleRequest(req, res, meta),
|
|
51
|
+
transformHtml: liveReloadEnabled
|
|
52
|
+
? (html) => liveReload.injectHtml(html)
|
|
53
|
+
: undefined,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const projectWatcher = createProjectWatcher(project, {
|
|
57
|
+
runInitialBuild: true,
|
|
58
|
+
logChanges: true,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// 成功した再ビルドのあとだけ reload(初回はクライアント未接続のため不要)
|
|
62
|
+
projectWatcher.on('build:success', ({ initial }) => {
|
|
63
|
+
if (!initial && liveReloadEnabled) {
|
|
64
|
+
liveReload.broadcastReload();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
let stopping = false;
|
|
69
|
+
let watcherStarted = false;
|
|
70
|
+
|
|
71
|
+
async function shutdown() {
|
|
72
|
+
if (stopping) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
stopping = true;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
if (watcherStarted) {
|
|
79
|
+
await projectWatcher.close();
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
// 終了時エラーは無視
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
liveReload.close();
|
|
87
|
+
} catch {
|
|
88
|
+
// 終了時エラーは無視
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
await staticServer.stop();
|
|
93
|
+
} catch {
|
|
94
|
+
// 終了時エラーは無視
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log('[JSKim] 開発サーバーを停止しました。');
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function failStartup(err) {
|
|
102
|
+
const message = err && err.message ? err.message : String(err);
|
|
103
|
+
console.error(message);
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
if (watcherStarted) {
|
|
107
|
+
await projectWatcher.close();
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
// ignore
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
liveReload.close();
|
|
115
|
+
} catch {
|
|
116
|
+
// ignore
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await staticServer.stop();
|
|
121
|
+
} catch {
|
|
122
|
+
// ignore
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// cleanup 完了後に終了する。
|
|
126
|
+
// IPC 接続があると exitCode だけではプロセスが残るため明示終了する。
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
registerShutdown(shutdown);
|
|
131
|
+
|
|
132
|
+
// 初回 build → server → watcher
|
|
133
|
+
await projectWatcher.start({ watchFiles: false });
|
|
134
|
+
watcherStarted = true;
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
await staticServer.start();
|
|
138
|
+
} catch (err) {
|
|
139
|
+
await failStartup(
|
|
140
|
+
formatListenError(err, {
|
|
141
|
+
projectName: project.name,
|
|
142
|
+
host,
|
|
143
|
+
port,
|
|
144
|
+
kind: '開発',
|
|
145
|
+
})
|
|
146
|
+
);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await projectWatcher.startWatching();
|
|
151
|
+
|
|
152
|
+
console.log('[JSKim] 開発サーバーを起動しました。');
|
|
153
|
+
console.log(`プロジェクト: ${project.name}`);
|
|
154
|
+
console.log(`ルート: ${outputDisplay}`);
|
|
155
|
+
console.log(`URL: ${staticServer.url}`);
|
|
156
|
+
console.log(
|
|
157
|
+
`ライブリロード: ${liveReloadEnabled ? '有効' : '無効'}`
|
|
158
|
+
);
|
|
159
|
+
console.log('終了するには Ctrl+C を押してください。');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = {
|
|
163
|
+
runDevCommand,
|
|
164
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI ヘルプ文言を返します。
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
7
|
+
function getHelpText() {
|
|
8
|
+
return [
|
|
9
|
+
'JSKim - Nunjucksを使用した静的HTMLビルド環境',
|
|
10
|
+
'',
|
|
11
|
+
'使用方法:',
|
|
12
|
+
' jskim <command> <project>',
|
|
13
|
+
'',
|
|
14
|
+
'コマンド:',
|
|
15
|
+
' build <project> 静的ファイルをビルドします。',
|
|
16
|
+
' watch <project> ファイルの変更を監視して再ビルドします。',
|
|
17
|
+
' serve <project> ビルド済みのファイルを配信します。',
|
|
18
|
+
' dev <project> ビルド・監視・サーバー・ライブリロードを起動します。',
|
|
19
|
+
'',
|
|
20
|
+
'オプション:',
|
|
21
|
+
' -h, --help ヘルプを表示します。',
|
|
22
|
+
' -v, --version バージョンを表示します。',
|
|
23
|
+
].join('\n');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 不明なコマンド時の案内を返します。
|
|
28
|
+
* @param {string} command
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
function getUnknownCommandText(command) {
|
|
32
|
+
return [
|
|
33
|
+
`[JSKim] 不明なコマンドです: ${command}`,
|
|
34
|
+
'',
|
|
35
|
+
'使用できるコマンド:',
|
|
36
|
+
' build <project>',
|
|
37
|
+
' watch <project>',
|
|
38
|
+
' serve <project>',
|
|
39
|
+
' dev <project>',
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
getHelpText,
|
|
45
|
+
getUnknownCommandText,
|
|
46
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ワークスペース相対の表示用パスへ変換します。
|
|
7
|
+
* @param {string} abs
|
|
8
|
+
* @param {string} workspaceRoot
|
|
9
|
+
* @returns {string}
|
|
10
|
+
*/
|
|
11
|
+
function toDisplayPath(abs, workspaceRoot) {
|
|
12
|
+
const rel = path.relative(workspaceRoot, abs);
|
|
13
|
+
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
14
|
+
return abs.split(path.sep).join('/');
|
|
15
|
+
}
|
|
16
|
+
return rel.split(path.sep).join('/');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
toDisplayPath,
|
|
21
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI の SIGINT/SIGTERM と内部検証用 IPC を登録します。
|
|
5
|
+
* @param {() => void|Promise<void>} shutdown
|
|
6
|
+
*/
|
|
7
|
+
function registerShutdown(shutdown) {
|
|
8
|
+
process.on('SIGINT', () => {
|
|
9
|
+
shutdown();
|
|
10
|
+
});
|
|
11
|
+
process.on('SIGTERM', () => {
|
|
12
|
+
shutdown();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (process.platform === 'win32' && process.stdin.isTTY) {
|
|
16
|
+
const readline = require('node:readline');
|
|
17
|
+
readline.createInterface({ input: process.stdin }).on('SIGINT', () => {
|
|
18
|
+
shutdown();
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 内部検証用 IPC(公開機能ではない。一般利用は Ctrl+C)
|
|
23
|
+
process.on('message', (msg) => {
|
|
24
|
+
if (msg === 'jskim:stop') {
|
|
25
|
+
shutdown();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
registerShutdown,
|
|
32
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { loadConfig } = require('../lib/load-config');
|
|
4
|
+
const { resolveProject } = require('../lib/resolve-project');
|
|
5
|
+
const { createStaticServer } = require('../lib/create-static-server');
|
|
6
|
+
const { registerShutdown } = require('./register-shutdown');
|
|
7
|
+
const { toDisplayPath } = require('./path-display');
|
|
8
|
+
const { assertOutputDirReady, formatListenError } = require('./serve-errors');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* serve コマンドを実行します。
|
|
12
|
+
* @param {object} options
|
|
13
|
+
* @param {string|undefined} options.projectName
|
|
14
|
+
* @param {string} [options.workspaceRoot]
|
|
15
|
+
* @param {string} [options.usageLine]
|
|
16
|
+
* @param {string} [options.buildHint]
|
|
17
|
+
* @returns {Promise<void>}
|
|
18
|
+
*/
|
|
19
|
+
async function runServeCommand(options = {}) {
|
|
20
|
+
const workspaceRoot = options.workspaceRoot || process.cwd();
|
|
21
|
+
const usageLine =
|
|
22
|
+
options.usageLine || 'npm run serve -- <project-name>';
|
|
23
|
+
|
|
24
|
+
const { config } = loadConfig(workspaceRoot);
|
|
25
|
+
const project = resolveProject({
|
|
26
|
+
config,
|
|
27
|
+
workspaceRoot,
|
|
28
|
+
projectName: options.projectName,
|
|
29
|
+
commandName: 'serve',
|
|
30
|
+
usageLine,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const buildHint =
|
|
34
|
+
options.buildHint || `npm run build -- ${project.name}`;
|
|
35
|
+
assertOutputDirReady(project, { buildHint });
|
|
36
|
+
|
|
37
|
+
const host = project.serve.host.trim();
|
|
38
|
+
const port = project.serve.port;
|
|
39
|
+
const outputDisplay = toDisplayPath(project.outputDir, workspaceRoot);
|
|
40
|
+
|
|
41
|
+
const staticServer = createStaticServer({
|
|
42
|
+
rootDir: project.outputDir,
|
|
43
|
+
host,
|
|
44
|
+
port,
|
|
45
|
+
projectName: project.name,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await staticServer.start();
|
|
50
|
+
} catch (err) {
|
|
51
|
+
throw formatListenError(err, {
|
|
52
|
+
projectName: project.name,
|
|
53
|
+
host,
|
|
54
|
+
port,
|
|
55
|
+
kind: '静的',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log('[JSKim] 静的サーバーを起動しました。');
|
|
60
|
+
console.log(`プロジェクト: ${project.name}`);
|
|
61
|
+
console.log(`ルート: ${outputDisplay}`);
|
|
62
|
+
console.log(`URL: ${staticServer.url}`);
|
|
63
|
+
console.log('終了するには Ctrl+C を押してください。');
|
|
64
|
+
|
|
65
|
+
let stopping = false;
|
|
66
|
+
|
|
67
|
+
async function shutdown() {
|
|
68
|
+
if (stopping) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
stopping = true;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
await staticServer.stop();
|
|
75
|
+
} catch {
|
|
76
|
+
// 終了時の close エラーは無視
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log('[JSKim] 静的サーバーを停止しました。');
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
registerShutdown(shutdown);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
runServeCommand,
|
|
88
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* serve / dev 開始前に outputDir の存在を確認します。
|
|
7
|
+
* @param {object} project
|
|
8
|
+
* @param {object} [options]
|
|
9
|
+
* @param {string} [options.buildHint]
|
|
10
|
+
*/
|
|
11
|
+
function assertOutputDirReady(project, options = {}) {
|
|
12
|
+
const { name, outputDir, outputDirConfig } = project;
|
|
13
|
+
const buildHint = options.buildHint || `npm run build -- ${name}`;
|
|
14
|
+
|
|
15
|
+
if (!outputDir || String(outputDir).trim() === '') {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`[JSKim] ビルド出力が見つかりません。\n` +
|
|
18
|
+
`プロジェクト: ${name}\n` +
|
|
19
|
+
`出力先: ${outputDirConfig || '(未設定)'}\n\n` +
|
|
20
|
+
`先にビルドを実行してください:\n` +
|
|
21
|
+
buildHint
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!fs.existsSync(outputDir)) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`[JSKim] ビルド出力が見つかりません。\n` +
|
|
28
|
+
`プロジェクト: ${name}\n` +
|
|
29
|
+
`出力先: ${outputDirConfig}\n\n` +
|
|
30
|
+
`先にビルドを実行してください:\n` +
|
|
31
|
+
buildHint
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!fs.statSync(outputDir).isDirectory()) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`[JSKim] ビルド出力が見つかりません。\n` +
|
|
38
|
+
`プロジェクト: ${name}\n` +
|
|
39
|
+
`出力先: ${outputDirConfig}\n` +
|
|
40
|
+
`原因: outputDir はディレクトリではありません。\n\n` +
|
|
41
|
+
`先にビルドを実行してください:\n` +
|
|
42
|
+
buildHint
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function formatListenError(err, { projectName, host, port, kind = '静的' }) {
|
|
48
|
+
const code = err && err.code;
|
|
49
|
+
|
|
50
|
+
if (code === 'EADDRINUSE') {
|
|
51
|
+
return new Error(
|
|
52
|
+
`[JSKim] ポート ${port} はすでに使用されています。\n` +
|
|
53
|
+
`プロジェクト: ${projectName}\n` +
|
|
54
|
+
`ホスト: ${host}\n\n` +
|
|
55
|
+
`jskim.config.js の serve.port を変更してください。`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (code === 'EACCES') {
|
|
60
|
+
return new Error(
|
|
61
|
+
`[JSKim] ポート ${port} へのバインド権限がありません。\n` +
|
|
62
|
+
`プロジェクト: ${projectName}\n` +
|
|
63
|
+
`ホスト: ${host}\n\n` +
|
|
64
|
+
`別の serve.port を指定するか、権限を確認してください。`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const message = err && err.message ? err.message : String(err);
|
|
69
|
+
const label = kind === '開発' ? '開発サーバー' : '静的サーバー';
|
|
70
|
+
return new Error(
|
|
71
|
+
`[JSKim] ${label}の起動に失敗しました。\n` +
|
|
72
|
+
`プロジェクト: ${projectName}\n` +
|
|
73
|
+
`ホスト: ${host}\n` +
|
|
74
|
+
`ポート: ${port}\n` +
|
|
75
|
+
`原因: ${message}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
assertOutputDirReady,
|
|
81
|
+
formatListenError,
|
|
82
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { loadConfig } = require('../lib/load-config');
|
|
4
|
+
const { resolveProject } = require('../lib/resolve-project');
|
|
5
|
+
const { createProjectWatcher } = require('../lib/create-project-watcher');
|
|
6
|
+
const { registerShutdown } = require('./register-shutdown');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* watch コマンドを実行します。
|
|
10
|
+
* @param {object} options
|
|
11
|
+
* @param {string|undefined} options.projectName
|
|
12
|
+
* @param {string} [options.workspaceRoot]
|
|
13
|
+
* @param {string} [options.usageLine]
|
|
14
|
+
* @returns {Promise<void>}
|
|
15
|
+
*/
|
|
16
|
+
async function runWatchCommand(options = {}) {
|
|
17
|
+
const workspaceRoot = options.workspaceRoot || process.cwd();
|
|
18
|
+
const usageLine =
|
|
19
|
+
options.usageLine || 'npm run watch -- <project-name>';
|
|
20
|
+
|
|
21
|
+
const { config } = loadConfig(workspaceRoot);
|
|
22
|
+
const project = resolveProject({
|
|
23
|
+
config,
|
|
24
|
+
workspaceRoot,
|
|
25
|
+
projectName: options.projectName,
|
|
26
|
+
commandName: 'watch',
|
|
27
|
+
usageLine,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const projectWatcher = createProjectWatcher(project, {
|
|
31
|
+
runInitialBuild: true,
|
|
32
|
+
logChanges: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
projectWatcher.on('ready', ({ displayPaths, debounceMs }) => {
|
|
36
|
+
console.log(`[JSKim] プロジェクトを監視しています: ${project.name}`);
|
|
37
|
+
console.log('パス:');
|
|
38
|
+
for (const display of displayPaths) {
|
|
39
|
+
console.log(`- ${display}`);
|
|
40
|
+
}
|
|
41
|
+
console.log('');
|
|
42
|
+
console.log(`Debounce: ${debounceMs}ms`);
|
|
43
|
+
console.log('終了するには Ctrl+C を押してください。');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await projectWatcher.start();
|
|
47
|
+
|
|
48
|
+
let stopping = false;
|
|
49
|
+
|
|
50
|
+
async function shutdown() {
|
|
51
|
+
if (stopping) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
stopping = true;
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
await projectWatcher.close();
|
|
58
|
+
} catch {
|
|
59
|
+
// 終了時エラーは無視
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log('[JSKim] ウォッチを停止しました。');
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
registerShutdown(shutdown);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
runWatchCommand,
|
|
71
|
+
};
|
package/scripts/dev.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { runDevCommand } = require('./commands/dev-command');
|
|
4
|
+
|
|
5
|
+
runDevCommand({
|
|
6
|
+
projectName: process.argv[2],
|
|
7
|
+
workspaceRoot: process.cwd(),
|
|
8
|
+
usageLine: 'npm run dev -- <project-name>',
|
|
9
|
+
}).catch((err) => {
|
|
10
|
+
const message = err && err.message ? err.message : String(err);
|
|
11
|
+
console.error(message);
|
|
12
|
+
process.exitCode = 1;
|
|
13
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { loadConfig } = require('./load-config');
|
|
5
|
+
const { resolveProject } = require('./resolve-project');
|
|
6
|
+
const { createNunjucksEnv } = require('./create-nunjucks-env');
|
|
7
|
+
const { cleanOutput } = require('./clean-output');
|
|
8
|
+
const { renderPages } = require('./render-pages');
|
|
9
|
+
const { copyFiles } = require('./copy-files');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 設定を読み込み、プロジェクトを解決してフルビルドを実行します。
|
|
13
|
+
*
|
|
14
|
+
* @param {string|undefined} projectName
|
|
15
|
+
* @param {object} [options]
|
|
16
|
+
* @param {string} [options.workspaceRoot]
|
|
17
|
+
* @param {string} [options.commandName='build']
|
|
18
|
+
* @param {string} [options.usageLine]
|
|
19
|
+
* @param {string} [options.logTitle='ビルドが完了しました']
|
|
20
|
+
* @param {boolean} [options.includeOutput=true]
|
|
21
|
+
* @param {boolean} [options.log=true]
|
|
22
|
+
* @returns {Promise<object>}
|
|
23
|
+
*/
|
|
24
|
+
async function buildProject(projectName, options = {}) {
|
|
25
|
+
const workspaceRoot =
|
|
26
|
+
options.workspaceRoot || process.cwd();
|
|
27
|
+
const commandName = options.commandName || 'build';
|
|
28
|
+
|
|
29
|
+
const { config } = loadConfig(workspaceRoot);
|
|
30
|
+
const project = resolveProject({
|
|
31
|
+
config,
|
|
32
|
+
workspaceRoot,
|
|
33
|
+
projectName,
|
|
34
|
+
commandName,
|
|
35
|
+
usageLine: options.usageLine,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return runBuild(project, options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 解決済みプロジェクトに対して clean → render → copy を実行します。
|
|
43
|
+
*
|
|
44
|
+
* @param {object} project
|
|
45
|
+
* @param {object} [options]
|
|
46
|
+
* @returns {Promise<object>}
|
|
47
|
+
*/
|
|
48
|
+
async function runBuild(project, options = {}) {
|
|
49
|
+
const logTitle = options.logTitle || 'ビルドが完了しました';
|
|
50
|
+
const includeOutput = options.includeOutput !== false;
|
|
51
|
+
const shouldLog = options.log !== false;
|
|
52
|
+
|
|
53
|
+
if (project.build.clean) {
|
|
54
|
+
await cleanOutput({
|
|
55
|
+
outputDir: project.outputDir,
|
|
56
|
+
sourceDir: project.sourceDir,
|
|
57
|
+
workspaceRoot: project.workspaceRoot,
|
|
58
|
+
projectName: project.name,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const env = createNunjucksEnv({
|
|
63
|
+
sourceDir: project.sourceDir,
|
|
64
|
+
templates: project.templates,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const { renderedCount } = await renderPages({ env, project });
|
|
68
|
+
const { copiedCount } = await copyFiles({ project });
|
|
69
|
+
|
|
70
|
+
const outputDisplay = path
|
|
71
|
+
.relative(project.workspaceRoot, project.outputDir)
|
|
72
|
+
.split(path.sep)
|
|
73
|
+
.join('/');
|
|
74
|
+
|
|
75
|
+
const result = {
|
|
76
|
+
project,
|
|
77
|
+
renderedCount,
|
|
78
|
+
copiedCount,
|
|
79
|
+
outputDisplay: outputDisplay || project.outputDir,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
if (shouldLog) {
|
|
83
|
+
printBuildResult(result, { logTitle, includeOutput });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function printBuildResult(result, options = {}) {
|
|
90
|
+
const logTitle = options.logTitle || 'ビルドが完了しました';
|
|
91
|
+
const includeOutput = options.includeOutput !== false;
|
|
92
|
+
|
|
93
|
+
console.log(`[JSKim] ${logTitle}`);
|
|
94
|
+
console.log(`プロジェクト: ${result.project.name}`);
|
|
95
|
+
console.log(`レンダリングしたページ数: ${result.renderedCount}`);
|
|
96
|
+
console.log(`コピーしたファイル数: ${result.copiedCount}`);
|
|
97
|
+
if (includeOutput) {
|
|
98
|
+
console.log(`出力先: ${result.outputDisplay}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
buildProject,
|
|
104
|
+
runBuild,
|
|
105
|
+
printBuildResult,
|
|
106
|
+
};
|