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 +32 -0
- package/core/server.mjs +34 -20
- package/core/watcher.mjs +2 -4
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
303
|
-
this.context.server.reloadCSS()
|
|
304
|
-
}, 100)
|
|
302
|
+
this.context.server.reloadCSS()
|
|
305
303
|
}
|
|
306
304
|
}
|
|
307
305
|
|