dsh-design-studio 0.4.1 → 0.6.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.en.md +19 -7
- package/README.md +46 -11
- package/cordis.patch.yml +1 -1
- package/lib/browser.js +273 -0
- package/lib/bundle.js +228 -0
- package/lib/client.js +1442 -47
- package/lib/core.js +263 -25
- package/lib/doc.js +356 -0
- package/lib/handoff.js +555 -0
- package/lib/history.js +1 -1
- package/lib/index.js +683 -24
- package/lib/look.js +550 -0
- package/lib/picker.js +1153 -24
- package/lib/serve.js +25 -8
- package/lib/system.js +1360 -0
- package/lib/tool.js +9 -3
- package/lib/tweaks.js +362 -0
- package/locale/tool/en.json +2 -2
- package/locale/tool/zh.json +2 -2
- package/package.json +1 -1
- package/skills/ui-design/SKILL.md +67 -3
- package/skills/ui-design/references/app.md +1 -1
package/lib/serve.js
CHANGED
|
@@ -25,7 +25,7 @@ const MAX_HTML = 8 * 1024 * 1024 // 要注入脚本的 HTML 最多读这么大
|
|
|
25
25
|
const UP_HOSTS = ['127.0.0.1', '::1'] // 开发服务器可能只听其中一个
|
|
26
26
|
const DEBOUNCE_MS = 120
|
|
27
27
|
|
|
28
|
-
const MIME = {
|
|
28
|
+
export const MIME = {
|
|
29
29
|
'.html': 'text/html; charset=utf-8',
|
|
30
30
|
'.htm': 'text/html; charset=utf-8',
|
|
31
31
|
'.css': 'text/css; charset=utf-8',
|
|
@@ -56,8 +56,9 @@ const MIME = {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// 改动通知里不算的:版本库、依赖、系统垃圾
|
|
59
|
-
const EXPORTS = /^(exports([\\/][^\\/]+\.png)?|refs([\\/][^\\/]+\.(png|jpe?g|gif|webp))?)$/i //
|
|
59
|
+
const EXPORTS = /^(exports([\\/][^\\/]+\.(png|pdf|pptx))?|refs([\\/][^\\/]+\.(png|jpe?g|gif|webp))?)$/i // 导出的图片 / PDF / PPT、参考图(和第一次建的 exports / refs 目录):不算设计改了
|
|
60
60
|
const IGNORED = /(^|[\\/])(\.git|node_modules|\.DS_Store|\.next|\.cache|\.turbo)([\\/]|$)/
|
|
61
|
+
const HANDOFF = /^handoff([\\/]|$)/i // 转成代码的交接包(说明和截图):不算设计改了,也别在截图时把页面刷掉
|
|
61
62
|
|
|
62
63
|
/** 只认本机名 + 自己的端口(防 DNS 重绑定:外站把域名解析到 127.0.0.1 也进不来) */
|
|
63
64
|
export function hostOk(host, port) {
|
|
@@ -65,11 +66,26 @@ export function hostOk(host, port) {
|
|
|
65
66
|
return h === `127.0.0.1:${port}` || h === `localhost:${port}` || h === `[::1]:${port}`
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* 最先跑的一小段:记下页面脚本报错、没载出来的样式表 / 脚本(设计体检报给模型)。
|
|
71
|
+
* picker 在 </body> 前,等它装上,前面脚本的报错早过去了
|
|
72
|
+
*/
|
|
73
|
+
export const ERR_CATCHER = '<script>(()=>{if(window.__dshErrs)return;const L=window.__dshErrs=[];const add=(x)=>{if(L.length<30)L.push(x)};' +
|
|
74
|
+
'addEventListener("error",(e)=>{const t=e.target;if(t&&t!==window&&t.tagName){add({res:1,tag:t.tagName.toLowerCase(),src:String(t.currentSrc||t.src||t.href||"").slice(0,300)})}' +
|
|
75
|
+
'else add({msg:String(e.message||"").slice(0,300),src:String(e.filename||"").slice(0,300),line:e.lineno||0})},true);' +
|
|
76
|
+
'addEventListener("unhandledrejection",(e)=>{const r=e.reason;add({msg:String((r&&r.message)||r).slice(0,300),src:"",line:0})})})()</script>'
|
|
77
|
+
|
|
78
|
+
/** 放进 <head> 最前面;没写 <head> 就放在 <html> / <!doctype> 后面(放到 doctype 前面页面会进怪异模式) */
|
|
79
|
+
export function headInsert(html, tag) {
|
|
80
|
+
const m = /<head\b[^>]*>/i.exec(html) || /<html\b[^>]*>/i.exec(html) || /^\s*<!doctype\b[^>]*>/i.exec(html)
|
|
81
|
+
return m ? html.slice(0, m.index + m[0].length) + tag + html.slice(m.index + m[0].length) : tag + html
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** 在 </body> 前(没有就在末尾)插入选取脚本,<head> 最前面放报错记录 */
|
|
69
85
|
export function injectPicker(html) {
|
|
70
86
|
const tag = `<script src="${INTERNAL}picker.js"></script>`
|
|
71
87
|
const i = html.toLowerCase().lastIndexOf('</body>')
|
|
72
|
-
return i >= 0 ? html.slice(0, i) + tag + html.slice(i) : html + tag
|
|
88
|
+
return headInsert(i >= 0 ? html.slice(0, i) + tag + html.slice(i) : html + tag, ERR_CATCHER)
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
/** 真实路径在不在根目录(也取真实路径)里面 */
|
|
@@ -142,7 +158,7 @@ export function trustedOrigins(hosts) {
|
|
|
142
158
|
|
|
143
159
|
/**
|
|
144
160
|
* @param opts.log 出错时写日志
|
|
145
|
-
* @param opts.onChange (key, file) 目录里有文件改了(file
|
|
161
|
+
* @param opts.onChange (key, file, files) 目录里有文件改了(file 目标;files:这一批的相对路径)
|
|
146
162
|
* @param opts.history 设计版本(lib/history.js):/__dsh_design__/v/<版本>/<文件> 给出那一版的文件
|
|
147
163
|
* @param opts.parents () → 还有哪些 DSH 页面的源能嵌预览(DSH 网页端的地址)
|
|
148
164
|
*/
|
|
@@ -256,15 +272,16 @@ export function createHub({ log = () => {}, onChange = () => {}, history = null,
|
|
|
256
272
|
try {
|
|
257
273
|
entry.watcher = fs.watch(entry.root, { recursive: true }, (_type, name) => {
|
|
258
274
|
const rel = String(name || '')
|
|
259
|
-
if (IGNORED.test(rel) || /(^|[\\/])\./.test(rel) || EXPORTS.test(rel)) return
|
|
275
|
+
if (IGNORED.test(rel) || /(^|[\\/])\./.test(rel) || EXPORTS.test(rel) || HANDOFF.test(rel)) return
|
|
260
276
|
last = rel
|
|
261
277
|
batch.add(rel.split(path.sep).join('/'))
|
|
262
278
|
clearTimeout(timer)
|
|
263
279
|
timer = setTimeout(() => {
|
|
264
|
-
|
|
280
|
+
// 一批改了太多文件就不列了(空的 = 不知道改了啥,页面整屏刷新),列一半会漏掉这一屏用到的
|
|
281
|
+
const files = batch.size > 50 ? [] : [...batch]
|
|
265
282
|
batch.clear()
|
|
266
283
|
for (const c of entry.clients) c.write(`event: change\ndata: ${JSON.stringify({ file: last, files })}\n\n`)
|
|
267
|
-
try { onChange(entry.key, path.join(entry.root, last)) } catch (e) { log(e) }
|
|
284
|
+
try { onChange(entry.key, path.join(entry.root, last), files) } catch (e) { log(e) }
|
|
268
285
|
}, DEBOUNCE_MS)
|
|
269
286
|
})
|
|
270
287
|
entry.watcher.on('error', (e) => log(e))
|