pugkit 1.0.0 → 1.0.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 CHANGED
@@ -136,6 +136,38 @@ img(src=info.src width=info.width height=info.height alt='')
136
136
 
137
137
  > **Note:** `imageInfo()`は`src/`配下の画像のみ対応しています。`public/`配下の画像は非対応です。
138
138
 
139
+ ### SVG Sprite
140
+
141
+ `src/` 配下の `icons/` ディレクトリに配置した SVG ファイルを1つのスプライトにまとめます。
142
+
143
+ #### ディレクトリ構成
144
+
145
+ ```
146
+ src/
147
+ └── assets/
148
+ └── icons/ # ここに SVG を配置
149
+ ├── arrow.svg
150
+ └── close.svg
151
+ ```
152
+
153
+ #### 出力
154
+
155
+ ```
156
+ dist/
157
+ └── assets/
158
+ └── icons.svg # 自動生成されるスプライト
159
+ ```
160
+
161
+ #### 使い方
162
+
163
+ ```html
164
+ <svg><use href="assets/icons.svg#arrow"></use></svg>
165
+ ```
166
+
167
+ - `icons/` ディレクトリは `src/` 配下の任意の場所に配置できます
168
+ - SVG ファイル名がそのまま `<symbol id>` になります
169
+ - `fill` / `stroke` は自動的に `currentColor` に変換されます(SVGの色をCSSで制御可能)
170
+
139
171
  ### Image Optimization
140
172
 
141
173
  ビルド時に自動的に画像を最適化します。
package/core/server.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import http from 'node:http'
2
2
  import path from 'node:path'
3
- import { existsSync, readFileSync } from 'node:fs'
4
- import { mkdir } from 'node:fs/promises'
3
+ import { existsSync } from 'node:fs'
4
+ import { mkdir, readFile } from 'node:fs/promises'
5
5
  import sirv from 'sirv'
6
6
  import { logger } from '../utils/logger.mjs'
7
7
 
@@ -17,7 +17,6 @@ const liveReloadScript = `<script>
17
17
  location.reload();
18
18
  });
19
19
  es.addEventListener('css-update', function() {
20
- // 同一オリジンの <link rel="stylesheet"> のみ再読み込み(外部フォント等は除外)
21
20
  document.querySelectorAll('link[rel="stylesheet"]').forEach(function(link) {
22
21
  var url = new URL(link.href);
23
22
  if (url.origin !== location.origin) return;
@@ -29,6 +28,9 @@ const liveReloadScript = `<script>
29
28
  es.close();
30
29
  setTimeout(function() { location.reload(); }, 1000);
31
30
  };
31
+ window.addEventListener('beforeunload', function() {
32
+ es.close();
33
+ });
32
34
  })();
33
35
  </script>`
34
36
 
@@ -73,7 +75,11 @@ export async function serverTask(context, options = {}) {
73
75
  })
74
76
  res.write('retry: 1000\n\n')
75
77
  clients.add(res)
76
- req.on('close', () => clients.delete(res))
78
+
79
+ const cleanup = () => clients.delete(res)
80
+ req.on('close', cleanup)
81
+ req.socket.on('close', cleanup)
82
+ res.on('error', cleanup)
77
83
  return
78
84
  }
79
85
 
@@ -87,22 +93,26 @@ export async function serverTask(context, options = {}) {
87
93
  const htmlFile = candidates.find(p => p.endsWith('.html') && existsSync(p))
88
94
 
89
95
  if (htmlFile) {
90
- try {
91
- let html = readFileSync(htmlFile, 'utf-8')
92
- html = html.includes('</body>')
93
- ? html.replace('</body>', liveReloadScript + '</body>')
94
- : html + liveReloadScript
95
- const buf = Buffer.from(html, 'utf-8')
96
- res.writeHead(200, {
97
- 'Content-Type': 'text/html; charset=utf-8',
98
- 'Content-Length': buf.length,
99
- 'Cache-Control': 'no-cache'
96
+ readFile(htmlFile, 'utf-8')
97
+ .then(html => {
98
+ html = html.includes('</body>')
99
+ ? html.replace('</body>', liveReloadScript + '</body>')
100
+ : html + liveReloadScript
101
+ const buf = Buffer.from(html, 'utf-8')
102
+ res.writeHead(200, {
103
+ 'Content-Type': 'text/html; charset=utf-8',
104
+ 'Content-Length': buf.length,
105
+ 'Cache-Control': 'no-cache'
106
+ })
107
+ res.end(buf)
100
108
  })
101
- res.end(buf)
102
- return
103
- } catch {
104
- // 読み込み失敗時は sirv にフォールスルー
105
- }
109
+ .catch(() => {
110
+ staticServe(req, res, () => {
111
+ res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' })
112
+ res.end('404 Not Found')
113
+ })
114
+ })
115
+ return
106
116
  }
107
117
 
108
118
  // ── sirv で静的ファイルを配信 ───────────────────────
@@ -115,7 +125,11 @@ export async function serverTask(context, options = {}) {
115
125
  function broadcast(event, data = '') {
116
126
  const msg = `event: ${event}\ndata: ${data}\n\n`
117
127
  for (const res of clients) {
118
- res.write(msg)
128
+ try {
129
+ res.write(msg)
130
+ } catch {
131
+ clients.delete(res)
132
+ }
119
133
  }
120
134
  }
121
135
 
package/core/watcher.mjs CHANGED
@@ -111,7 +111,7 @@ class FileWatcher {
111
111
  ignoreInitial: true,
112
112
  ignored: [/(^|[\/\\])\../, /node_modules/, /\.git/],
113
113
  persistent: true,
114
- awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 50 }
114
+ awaitWriteFinish: { stabilityThreshold: 50, pollInterval: 25 }
115
115
  })
116
116
 
117
117
  watcher.on('change', async path => {
@@ -299,9 +299,7 @@ class FileWatcher {
299
299
  */
300
300
  injectCSS() {
301
301
  if (this.context.server) {
302
- setTimeout(() => {
303
- this.context.server.reloadCSS()
304
- }, 100)
302
+ this.context.server.reloadCSS()
305
303
  }
306
304
  }
307
305
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pugkit",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A build tool for Pug-based projects",
5
5
  "type": "module",
6
6
  "license": "MIT",