pugkit 1.1.0 → 1.2.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 +34 -39
- package/config/defaults.mjs +1 -0
- package/config/main.mjs +1 -0
- package/config/patterns.mjs +3 -12
- package/core/builder.mjs +7 -1
- package/core/context.mjs +2 -0
- package/core/graph.mjs +1 -1
- package/core/watcher.mjs +19 -5
- package/package.json +2 -2
- package/tasks/pug.mjs +1 -1
- package/tasks/sass.mjs +51 -9
- package/tasks/script.mjs +51 -10
- package/transform/html.mjs +13 -9
package/README.md
CHANGED
|
@@ -9,11 +9,6 @@
|
|
|
9
9
|
</a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
## About
|
|
13
|
-
|
|
14
|
-
pugkitは静的サイト制作に特化したビルドツールです。
|
|
15
|
-
納品向きの綺麗なHTMLと、ファイル構成に制約のないアセットファイルを出力可能です。
|
|
16
|
-
|
|
17
12
|
## How To Use
|
|
18
13
|
|
|
19
14
|
```sh
|
|
@@ -39,6 +34,34 @@ $ touch ./src/index.pug
|
|
|
39
34
|
| `pugkit build` | 本番ビルド |
|
|
40
35
|
| `pugkit sprite` | SVGスプライト生成 |
|
|
41
36
|
|
|
37
|
+
## Directory Structure
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
project-root/
|
|
41
|
+
├── src/ # ソースファイル
|
|
42
|
+
│ ├── *.pug
|
|
43
|
+
│ ├── *.scss
|
|
44
|
+
│ ├── *.ts
|
|
45
|
+
│ ├── *.js
|
|
46
|
+
│ ├── *.jpg
|
|
47
|
+
│ ├── *.png
|
|
48
|
+
│ └── *.svg
|
|
49
|
+
├── public/ # 静的ファイル
|
|
50
|
+
│ ├── ogp.jpg
|
|
51
|
+
│ └── favicon.ico
|
|
52
|
+
├── dist/ # ビルド出力先
|
|
53
|
+
└── pugkit.config.mjs # ビルド設定ファイル
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### File Naming Rules
|
|
57
|
+
|
|
58
|
+
`_`(アンダースコア)で始まるファイル・ディレクトリはビルド対象外です。それ以外のファイルは `src/` 配下のディレクトリ構成を維持したまま `dist/` に出力されます。
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
src/foo/style.scss → dist/foo/style.css
|
|
62
|
+
src/foo/bar/script.js → dist/foo/bar/script.js
|
|
63
|
+
```
|
|
64
|
+
|
|
42
65
|
## Configuration
|
|
43
66
|
|
|
44
67
|
プロジェクトルートに`pugkit.config.mjs`を配置することで、ビルド設定をカスタマイズできます。
|
|
@@ -70,7 +93,7 @@ export default defineConfig({
|
|
|
70
93
|
| `server.port` | 開発サーバーのポート番号 | `number` | `5555` |
|
|
71
94
|
| `server.host` | 開発サーバーのホスト | `string` | `'localhost'` |
|
|
72
95
|
| `server.startPath` | サーバー起動時に開くパス | `string` | `'/'` |
|
|
73
|
-
| `
|
|
96
|
+
| `build.clean` | ビルド前に `dist/` をクリーンするか(`false` にすると他リソースと共存可能) | `boolean` | `true` |
|
|
74
97
|
| `build.imageOptimization` | 画像最適化の方式 | `'webp'` \| `'compress'` \| `false` | `'webp'` |
|
|
75
98
|
| `build.imageOptions.webp` | WebP変換オプション([Sharp WebP options](https://sharp.pixelplumbing.com/api-output#webp)) | `object` | - |
|
|
76
99
|
| `build.imageOptions.jpeg` | JPEG圧縮オプション([Sharp JPEG options](https://sharp.pixelplumbing.com/api-output#jpeg)) | `object` | - |
|
|
@@ -176,9 +199,13 @@ npm install --save-dev typescript
|
|
|
176
199
|
- `'compress'` - 元の形式を維持したまま圧縮
|
|
177
200
|
- `false` - 最適化を無効化
|
|
178
201
|
|
|
202
|
+
### SVG Optimization
|
|
203
|
+
|
|
204
|
+
`icons/`以外に配置した SVG ファイルはSVGOで自動最適化されて出力されます。
|
|
205
|
+
|
|
179
206
|
### SVG Sprite
|
|
180
207
|
|
|
181
|
-
`src
|
|
208
|
+
`src/`配下の`icons/`ディレクトリに配置したSVGを1つのスプライトファイルにまとめます。
|
|
182
209
|
|
|
183
210
|
```
|
|
184
211
|
src/assets/icons/arrow.svg → dist/assets/icons.svg#arrow
|
|
@@ -191,10 +218,6 @@ src/assets/icons/arrow.svg → dist/assets/icons.svg#arrow
|
|
|
191
218
|
- SVG ファイル名がそのまま `<symbol id>` になります
|
|
192
219
|
- `fill` / `stroke` は自動的に `currentColor` に変換されます
|
|
193
220
|
|
|
194
|
-
### SVG Optimization
|
|
195
|
-
|
|
196
|
-
`icons/` 以外に配置した SVG ファイルは SVGO で自動最適化されて出力されます。
|
|
197
|
-
|
|
198
221
|
### Public Directory
|
|
199
222
|
|
|
200
223
|
`public/` に置いたファイルはそのまま `dist/` のルートにコピーされます。faviconやOGP画像など最適化不要なファイルの置き場として使用します。
|
|
@@ -208,34 +231,6 @@ src/assets/icons/arrow.svg → dist/assets/icons.svg#arrow
|
|
|
208
231
|
| CSS | minify済み | expanded + ソースマップ |
|
|
209
232
|
| JS | minify済み・`console.*` 削除 | ソースマップ・`console.*` 保持 |
|
|
210
233
|
|
|
211
|
-
### File Naming Rules
|
|
212
|
-
|
|
213
|
-
`_`(アンダースコア)で始まるファイル・ディレクトリはビルド対象外です。それ以外のファイルは `src/` 配下のディレクトリ構成を維持したまま `dist/` に出力されます。
|
|
214
|
-
|
|
215
|
-
```
|
|
216
|
-
src/foo/style.scss → dist/foo/style.css
|
|
217
|
-
src/foo/bar/script.js → dist/foo/bar/script.js
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## Directory Structure
|
|
221
|
-
|
|
222
|
-
```
|
|
223
|
-
project-root/
|
|
224
|
-
├── src/ # ソースファイル
|
|
225
|
-
│ ├── *.pug
|
|
226
|
-
│ ├── *.scss
|
|
227
|
-
│ ├── *.ts
|
|
228
|
-
│ ├── *.js
|
|
229
|
-
│ ├── *.jpg
|
|
230
|
-
│ ├── *.png
|
|
231
|
-
│ └── *.svg
|
|
232
|
-
├── public/ # 静的ファイル
|
|
233
|
-
│ ├── ogp.jpg
|
|
234
|
-
│ └── favicon.ico
|
|
235
|
-
├── dist/ # ビルド出力先
|
|
236
|
-
└── pugkit.config.mjs # ビルド設定ファイル
|
|
237
|
-
```
|
|
238
|
-
|
|
239
234
|
## Tech Stack
|
|
240
235
|
|
|
241
236
|
- [Pug](https://pugjs.org/) - HTMLテンプレートエンジン
|
package/config/defaults.mjs
CHANGED
package/config/main.mjs
CHANGED
|
@@ -25,6 +25,7 @@ function mergeConfig(defaults, user) {
|
|
|
25
25
|
build: {
|
|
26
26
|
...defaults.build,
|
|
27
27
|
...(user.build || {}),
|
|
28
|
+
clean: user.build?.clean !== undefined ? user.build.clean : defaults.build.clean,
|
|
28
29
|
imageOptions: {
|
|
29
30
|
webp: { ...defaults.build.imageOptions.webp, ...(user.build?.imageOptions?.webp || {}) },
|
|
30
31
|
jpeg: { ...defaults.build.imageOptions.jpeg, ...(user.build?.imageOptions?.jpeg || {}) },
|
package/config/patterns.mjs
CHANGED
|
@@ -11,20 +11,11 @@ export function createGlobPatterns(srcPath) {
|
|
|
11
11
|
ignore: ['**/*.d.ts', '**/node_modules/**']
|
|
12
12
|
},
|
|
13
13
|
images: {
|
|
14
|
-
optimize: [
|
|
15
|
-
|
|
16
|
-
`!${srcPath}/**/sprites_*/*`,
|
|
17
|
-
`!${srcPath}/**/_inline*/*`,
|
|
18
|
-
`!${srcPath}/**/icons*/*`
|
|
19
|
-
],
|
|
20
|
-
webp: {
|
|
21
|
-
src: [`${srcPath}/**/*.{png,jpg,jpeg,gif}`],
|
|
22
|
-
ignore: [`!${srcPath}/**/favicons/*`, `!${srcPath}/**/ogp.{png,jpg}`]
|
|
23
|
-
}
|
|
14
|
+
optimize: [`${srcPath}/**/*.{png,jpg,jpeg}`, `!${srcPath}/**/icons/*`],
|
|
15
|
+
webp: [`${srcPath}/**/*.{png,jpg,jpeg,gif}`, `!${srcPath}/**/icons/*`]
|
|
24
16
|
},
|
|
25
17
|
svg: {
|
|
26
|
-
src: [`${srcPath}/**/*.svg
|
|
27
|
-
ignore: [`!${srcPath}/**/sprites_*/*`, `!${srcPath}/**/_inline*/*`, `!${srcPath}/**/icons*/*`]
|
|
18
|
+
src: [`${srcPath}/**/*.svg`, `!${srcPath}/**/icons/*`]
|
|
28
19
|
}
|
|
29
20
|
}
|
|
30
21
|
}
|
package/core/builder.mjs
CHANGED
|
@@ -34,11 +34,17 @@ export class Builder {
|
|
|
34
34
|
const { context } = this
|
|
35
35
|
const startTime = Date.now()
|
|
36
36
|
|
|
37
|
+
const shouldClean = context.config.build.clean
|
|
38
|
+
|
|
37
39
|
logger.info('build', `Building in ${context.mode} mode`)
|
|
38
40
|
|
|
39
41
|
try {
|
|
40
42
|
// 1. クリーンアップ
|
|
41
|
-
|
|
43
|
+
if (shouldClean) {
|
|
44
|
+
await this.clean()
|
|
45
|
+
} else {
|
|
46
|
+
logger.info('build', 'Skipping clean (clean: false)')
|
|
47
|
+
}
|
|
42
48
|
|
|
43
49
|
// 2. 並列ビルド(軽量タスク + スプライト)
|
|
44
50
|
const parallelTasks = []
|
package/core/context.mjs
CHANGED
package/core/graph.mjs
CHANGED
package/core/watcher.mjs
CHANGED
|
@@ -25,9 +25,18 @@ class FileWatcher {
|
|
|
25
25
|
|
|
26
26
|
// 初回ビルド(依存関係グラフ構築のため)
|
|
27
27
|
logger.info('watch', 'Building initial dependency graph...')
|
|
28
|
+
|
|
29
|
+
const initialTasks = []
|
|
28
30
|
if (this.context.taskRegistry?.pug) {
|
|
29
|
-
|
|
31
|
+
initialTasks.push(this.context.taskRegistry.pug(this.context))
|
|
32
|
+
}
|
|
33
|
+
if (this.context.taskRegistry?.sass) {
|
|
34
|
+
initialTasks.push(this.context.taskRegistry.sass(this.context))
|
|
30
35
|
}
|
|
36
|
+
if (this.context.taskRegistry?.script) {
|
|
37
|
+
initialTasks.push(this.context.taskRegistry.script(this.context))
|
|
38
|
+
}
|
|
39
|
+
await Promise.all(initialTasks)
|
|
31
40
|
|
|
32
41
|
this.watcher = chokidar
|
|
33
42
|
.watch([paths.src, paths.public], {
|
|
@@ -55,6 +64,9 @@ class FileWatcher {
|
|
|
55
64
|
|
|
56
65
|
handleAdd(filePath) {
|
|
57
66
|
if (this.isPublic(filePath)) return this.onPublicChange(filePath, 'add')
|
|
67
|
+
if (filePath.endsWith('.pug')) return this.onPugChange(filePath)
|
|
68
|
+
if (filePath.endsWith('.scss')) return this.onSassChange(filePath)
|
|
69
|
+
if (this.isScript(filePath)) return this.onScriptChange(filePath)
|
|
58
70
|
if (filePath.endsWith('.svg') && !this.isIcons(filePath)) return this.onSvgChange(filePath, 'add')
|
|
59
71
|
if (/\.(jpg|jpeg|png|gif)$/i.test(filePath)) return this.onImageChange(filePath, 'add')
|
|
60
72
|
}
|
|
@@ -122,7 +134,7 @@ class FileWatcher {
|
|
|
122
134
|
const relPath = relative(this.context.paths.src, filePath)
|
|
123
135
|
logger.info('change', `sass: ${relPath}`)
|
|
124
136
|
try {
|
|
125
|
-
if (this.context.taskRegistry?.sass) await this.context.taskRegistry.sass(this.context)
|
|
137
|
+
if (this.context.taskRegistry?.sass) await this.context.taskRegistry.sass(this.context, { files: [filePath] })
|
|
126
138
|
this.injectCSS()
|
|
127
139
|
} catch (error) {
|
|
128
140
|
logger.error('watch', `Sass build failed: ${error.message}`)
|
|
@@ -130,8 +142,9 @@ class FileWatcher {
|
|
|
130
142
|
}
|
|
131
143
|
|
|
132
144
|
async onSassUnlink(filePath) {
|
|
133
|
-
const { paths } = this.context
|
|
145
|
+
const { paths, sassGraph } = this.context
|
|
134
146
|
const relPath = relative(paths.src, filePath)
|
|
147
|
+
sassGraph.clearDependencies(filePath)
|
|
135
148
|
if (basename(filePath).startsWith('_')) {
|
|
136
149
|
logger.info('unlink', relPath)
|
|
137
150
|
return
|
|
@@ -146,7 +159,7 @@ class FileWatcher {
|
|
|
146
159
|
const relPath = relative(this.context.paths.src, filePath)
|
|
147
160
|
logger.info('change', `script: ${relPath}`)
|
|
148
161
|
try {
|
|
149
|
-
if (this.context.taskRegistry?.script) await this.context.taskRegistry.script(this.context)
|
|
162
|
+
if (this.context.taskRegistry?.script) await this.context.taskRegistry.script(this.context, { files: [filePath] })
|
|
150
163
|
this.reload()
|
|
151
164
|
} catch (error) {
|
|
152
165
|
logger.error('watch', `Script build failed: ${error.message}`)
|
|
@@ -154,8 +167,9 @@ class FileWatcher {
|
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
async onScriptUnlink(filePath) {
|
|
157
|
-
const { paths } = this.context
|
|
170
|
+
const { paths, scriptGraph } = this.context
|
|
158
171
|
const relPath = relative(paths.src, filePath)
|
|
172
|
+
scriptGraph.clearDependencies(filePath)
|
|
159
173
|
if (basename(filePath).startsWith('_')) {
|
|
160
174
|
logger.info('unlink', relPath)
|
|
161
175
|
return
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pugkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A build tool for Pug-based projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"esbuild": "^0.25.5",
|
|
50
50
|
"glob": "^13.0.6",
|
|
51
51
|
"image-size": "^2.0.2",
|
|
52
|
+
"js-beautify": "^1.15.4",
|
|
52
53
|
"picocolors": "^1.1.1",
|
|
53
54
|
"postcss": "^8.4.49",
|
|
54
|
-
"prettier": "^3.8.0",
|
|
55
55
|
"pug": "^3.0.3",
|
|
56
56
|
"sass": "^1.89.2",
|
|
57
57
|
"sharp": "^0.34.2",
|
package/tasks/pug.mjs
CHANGED
|
@@ -69,7 +69,7 @@ async function processFile(filePath, context) {
|
|
|
69
69
|
const imageInfo = createImageInfoHelper(filePath, paths, logger, config)
|
|
70
70
|
|
|
71
71
|
const html = template({ Builder: builderVars, imageSize, imageInfo })
|
|
72
|
-
const formatted =
|
|
72
|
+
const formatted = formatHtml(html)
|
|
73
73
|
await generatePage(filePath, formatted, paths)
|
|
74
74
|
} catch (error) {
|
|
75
75
|
logger.error('pug', `Failed: ${basename(filePath)} - ${error.message}`)
|
package/tasks/sass.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { glob } from 'glob'
|
|
2
2
|
import { readFile, writeFile } from 'node:fs/promises'
|
|
3
3
|
import { relative, resolve, basename, extname } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
4
5
|
import * as sass from 'sass'
|
|
5
6
|
import postcss from 'postcss'
|
|
6
7
|
import autoprefixer from 'autoprefixer'
|
|
@@ -12,36 +13,64 @@ import { ensureFileDir } from '../utils/file.mjs'
|
|
|
12
13
|
* Sassビルドタスク
|
|
13
14
|
*/
|
|
14
15
|
export async function sassTask(context, options = {}) {
|
|
15
|
-
const { paths, config, isProduction } = context
|
|
16
|
+
const { paths, config, isProduction, isDevelopment, sassGraph, cache } = context
|
|
16
17
|
|
|
17
18
|
// debugモードはdevモード時のみ有効
|
|
18
19
|
const isDebugMode = !isProduction && config.debug
|
|
19
20
|
|
|
20
|
-
// 1.
|
|
21
|
-
const
|
|
21
|
+
// 1. ビルド対象ファイルの取得(非パーシャル)
|
|
22
|
+
const allEntryFiles = await glob('**/[^_]*.scss', {
|
|
22
23
|
cwd: paths.src,
|
|
23
24
|
absolute: true,
|
|
24
25
|
ignore: ['**/_*.scss']
|
|
25
26
|
})
|
|
26
27
|
|
|
27
|
-
if (
|
|
28
|
+
if (allEntryFiles.length === 0) {
|
|
28
29
|
logger.skip('sass', 'No files to build')
|
|
29
30
|
return
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
// 2. dev モードでのインクリメンタルビルド
|
|
34
|
+
let filesToBuild = allEntryFiles
|
|
35
|
+
|
|
36
|
+
if (isDevelopment && options.files?.length > 0) {
|
|
37
|
+
const changedFile = options.files[0]
|
|
38
|
+
const isPartial = basename(changedFile).startsWith('_')
|
|
39
|
+
|
|
40
|
+
if (isPartial) {
|
|
41
|
+
// パーシャル変更 → 依存グラフから影響を受けるエントリファイルを特定
|
|
42
|
+
const affected = sassGraph.getAffectedParents(changedFile)
|
|
43
|
+
filesToBuild = affected.filter(f => allEntryFiles.includes(f))
|
|
44
|
+
|
|
45
|
+
if (filesToBuild.length === 0) {
|
|
46
|
+
// グラフにまだ情報がない場合はフルビルド
|
|
47
|
+
filesToBuild = allEntryFiles
|
|
48
|
+
} else {
|
|
49
|
+
logger.info('sass', `Partial changed, rebuilding ${filesToBuild.length} affected file(s)`)
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
// 非パーシャル変更 → そのファイルだけリビルド
|
|
53
|
+
filesToBuild = allEntryFiles.filter(f => f === changedFile)
|
|
54
|
+
if (filesToBuild.length === 0) {
|
|
55
|
+
logger.skip('sass', 'Changed file is not a build target')
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
logger.info('sass', `Building ${filesToBuild.length} file(s)`)
|
|
33
62
|
|
|
34
|
-
//
|
|
35
|
-
await Promise.all(
|
|
63
|
+
// 3. 並列コンパイル
|
|
64
|
+
await Promise.all(filesToBuild.map(file => compileSassFile(file, context, isDebugMode)))
|
|
36
65
|
|
|
37
|
-
logger.success('sass', `Built ${
|
|
66
|
+
logger.success('sass', `Built ${filesToBuild.length} file(s)`)
|
|
38
67
|
}
|
|
39
68
|
|
|
40
69
|
/**
|
|
41
70
|
* 個別Sassファイルのコンパイル
|
|
42
71
|
*/
|
|
43
72
|
async function compileSassFile(filePath, context, isDebugMode) {
|
|
44
|
-
const { paths, config, isProduction } = context
|
|
73
|
+
const { paths, config, isProduction, sassGraph } = context
|
|
45
74
|
|
|
46
75
|
try {
|
|
47
76
|
// Sassコンパイル
|
|
@@ -55,6 +84,19 @@ async function compileSassFile(filePath, context, isDebugMode) {
|
|
|
55
84
|
sourceMapIncludeSources: isDebugMode
|
|
56
85
|
})
|
|
57
86
|
|
|
87
|
+
// 依存グラフを更新(loadedUrls からパーシャルの依存関係を構築)
|
|
88
|
+
sassGraph.clearDependencies(filePath)
|
|
89
|
+
if (result.loadedUrls) {
|
|
90
|
+
for (const url of result.loadedUrls) {
|
|
91
|
+
if (url.protocol === 'file:') {
|
|
92
|
+
const depPath = fileURLToPath(url)
|
|
93
|
+
if (depPath !== filePath) {
|
|
94
|
+
sassGraph.addDependency(filePath, depPath)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
58
100
|
let css = result.css
|
|
59
101
|
|
|
60
102
|
// PostCSS処理
|
package/tasks/script.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { glob } from 'glob'
|
|
2
|
-
import { resolve, relative, dirname } from 'node:path'
|
|
2
|
+
import { resolve, relative, dirname, basename } from 'node:path'
|
|
3
3
|
import * as esbuild from 'esbuild'
|
|
4
4
|
import { logger } from '../utils/logger.mjs'
|
|
5
5
|
import { ensureDir } from '../utils/file.mjs'
|
|
@@ -8,29 +8,53 @@ import { ensureDir } from '../utils/file.mjs'
|
|
|
8
8
|
* esbuild(TypeScript/JavaScript)ビルドタスク
|
|
9
9
|
*/
|
|
10
10
|
export async function scriptTask(context, options = {}) {
|
|
11
|
-
const { paths, isProduction, config } = context
|
|
11
|
+
const { paths, isProduction, isDevelopment, config, scriptGraph } = context
|
|
12
12
|
|
|
13
13
|
// 1. ビルド対象ファイルの取得
|
|
14
|
-
const
|
|
14
|
+
const allEntryFiles = await glob('**/[^_]*.{ts,js}', {
|
|
15
15
|
cwd: paths.src,
|
|
16
16
|
absolute: true,
|
|
17
17
|
ignore: ['**/*.d.ts', '**/node_modules/**']
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
if (
|
|
20
|
+
if (allEntryFiles.length === 0) {
|
|
21
21
|
logger.skip('script', 'No files to build')
|
|
22
22
|
return
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// 2. dev モードでのインクリメンタルビルド
|
|
26
|
+
let filesToBuild = allEntryFiles
|
|
27
|
+
|
|
28
|
+
if (isDevelopment && options.files?.length > 0) {
|
|
29
|
+
const changedFile = options.files[0]
|
|
30
|
+
const isPartial = basename(changedFile).startsWith('_')
|
|
31
|
+
|
|
32
|
+
if (isPartial) {
|
|
33
|
+
// パーシャル変更 → 依存グラフから影響を受けるエントリファイルを特定
|
|
34
|
+
const affected = scriptGraph.getAffectedParents(changedFile)
|
|
35
|
+
filesToBuild = affected.filter(f => allEntryFiles.includes(f))
|
|
36
|
+
|
|
37
|
+
if (filesToBuild.length === 0) {
|
|
38
|
+
// グラフにまだ情報がない場合はフルビルド
|
|
39
|
+
filesToBuild = allEntryFiles
|
|
40
|
+
} else {
|
|
41
|
+
logger.info('script', `Partial changed, rebuilding ${filesToBuild.length} affected file(s)`)
|
|
42
|
+
}
|
|
43
|
+
} else if (allEntryFiles.includes(changedFile)) {
|
|
44
|
+
// 非パーシャルのエントリファイル → そのファイルだけリビルド
|
|
45
|
+
filesToBuild = [changedFile]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
logger.info('script', `Building ${filesToBuild.length} file(s)`)
|
|
26
50
|
|
|
27
51
|
// debugモードはdevモード時のみ有効
|
|
28
52
|
const isDebugMode = !isProduction && config.debug
|
|
29
53
|
|
|
30
54
|
try {
|
|
31
|
-
//
|
|
55
|
+
// 3. esbuild設定
|
|
32
56
|
const esbuildConfig = {
|
|
33
|
-
entryPoints:
|
|
57
|
+
entryPoints: filesToBuild,
|
|
34
58
|
outdir: paths.dist,
|
|
35
59
|
outbase: paths.src,
|
|
36
60
|
bundle: true,
|
|
@@ -41,7 +65,7 @@ export async function scriptTask(context, options = {}) {
|
|
|
41
65
|
write: true,
|
|
42
66
|
sourcemap: isDebugMode,
|
|
43
67
|
minify: false,
|
|
44
|
-
metafile:
|
|
68
|
+
metafile: true,
|
|
45
69
|
logLevel: 'error',
|
|
46
70
|
keepNames: false,
|
|
47
71
|
external: [],
|
|
@@ -57,7 +81,7 @@ export async function scriptTask(context, options = {}) {
|
|
|
57
81
|
esbuildConfig.drop = ['console', 'debugger']
|
|
58
82
|
}
|
|
59
83
|
|
|
60
|
-
//
|
|
84
|
+
// 4. ビルド実行
|
|
61
85
|
await ensureDir(paths.dist)
|
|
62
86
|
const result = await esbuild.build(esbuildConfig)
|
|
63
87
|
|
|
@@ -65,7 +89,24 @@ export async function scriptTask(context, options = {}) {
|
|
|
65
89
|
throw new Error(`esbuild errors: ${result.errors.length}`)
|
|
66
90
|
}
|
|
67
91
|
|
|
68
|
-
|
|
92
|
+
// 5. 依存グラフを更新(metafile から依存関係を構築)
|
|
93
|
+
if (result.metafile) {
|
|
94
|
+
for (const [output, meta] of Object.entries(result.metafile.outputs)) {
|
|
95
|
+
if (!meta.entryPoint) continue
|
|
96
|
+
const entryPath = resolve(paths.root, meta.entryPoint)
|
|
97
|
+
|
|
98
|
+
scriptGraph.clearDependencies(entryPath)
|
|
99
|
+
|
|
100
|
+
for (const inputPath of Object.keys(meta.inputs)) {
|
|
101
|
+
const absInputPath = resolve(paths.root, inputPath)
|
|
102
|
+
if (absInputPath !== entryPath) {
|
|
103
|
+
scriptGraph.addDependency(entryPath, absInputPath)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
logger.success('script', `Built ${filesToBuild.length} file(s)`)
|
|
69
110
|
} catch (error) {
|
|
70
111
|
logger.error('script', error.message)
|
|
71
112
|
throw error
|
package/transform/html.mjs
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import pkg from 'js-beautify'
|
|
2
|
+
const { html: beautifyHtml } = pkg
|
|
2
3
|
|
|
3
|
-
export
|
|
4
|
+
export function formatHtml(html, options = {}) {
|
|
4
5
|
const cleaned = html.replace(/[\u200B-\u200D\uFEFF]/g, '')
|
|
5
6
|
|
|
6
|
-
return
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
return beautifyHtml(cleaned, {
|
|
8
|
+
indent_size: options.tabWidth || 2,
|
|
9
|
+
indent_with_tabs: options.useTabs || false,
|
|
10
|
+
max_preserve_newlines: 1,
|
|
11
|
+
preserve_newlines: false,
|
|
12
|
+
end_with_newline: true,
|
|
13
|
+
extra_liners: [],
|
|
14
|
+
wrap_line_length: 0,
|
|
15
|
+
inline: [],
|
|
16
|
+
content_unformatted: ['script', 'style', 'pre']
|
|
13
17
|
})
|
|
14
18
|
}
|