create-yoya-ui 0.1.0 → 0.1.2
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 +23 -0
- package/bin/create-yoya-ui.js +20 -4
- package/package.json +2 -2
- package/templates/admin/README.md +25 -0
- package/templates/admin/index.html +12 -0
- package/templates/admin/package.json +17 -0
- package/templates/admin/src/main.js +166 -0
- package/templates/admin/vite.config.js +7 -0
- package/templates/basic/package.json +1 -1
- package/templates/ssr/README.md +32 -0
- package/templates/ssr/package.json +17 -0
- package/templates/ssr/src/client.js +6 -0
- package/templates/ssr/src/home-page.js +21 -0
- package/templates/ssr/src/server.mjs +48 -0
- package/templates/ssr/vite.config.js +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# create-yoya-ui
|
|
2
|
+
|
|
3
|
+
快速搭建 [yoya-ui](https://github.com/yoyaflow/yoya-ui) 项目的脚手架。
|
|
4
|
+
|
|
5
|
+
## 用法
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx create-yoya-ui@latest my-app # basic 模板(SPA)
|
|
9
|
+
npx create-yoya-ui@latest my-app --template ssr # SSR 模板
|
|
10
|
+
npx create-yoya-ui@latest my-app --template admin # 后台管理模板
|
|
11
|
+
cd my-app
|
|
12
|
+
npm install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- **basic**:默认模板,`npm run dev` 启动 Vite 开发服务器
|
|
16
|
+
- **ssr**:服务端渲染模板,`npm run build && npm start`(renderPage 整页渲染 + hydrateOrMount 客户端接入)
|
|
17
|
+
- **admin**:标准后台管理模板(顶部导航 + 可折叠侧栏 + RouterViews 内容区)
|
|
18
|
+
|
|
19
|
+
## 模板内容
|
|
20
|
+
|
|
21
|
+
- `templates/basic`:页面壳、按钮事件、表单收集校验、主题切换
|
|
22
|
+
- `templates/ssr`:home-page.js(页面组件 + 词典)、server.mjs(node:http + renderPage)、client.js(hydrateOrMount)
|
|
23
|
+
- `templates/admin`:管理后台壳(logo/系统名、顶级导航、用户头像、可折叠菜单、带标题内容区)
|
package/bin/create-yoya-ui.js
CHANGED
|
@@ -4,10 +4,18 @@ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync
|
|
|
4
4
|
import { join, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
|
|
7
|
-
const templateDir = resolve(fileURLToPath(new URL('../templates/basic', import.meta.url)));
|
|
8
7
|
const args = process.argv.slice(2);
|
|
9
8
|
const targetName = args[0] || 'yoya-ui-app';
|
|
10
9
|
const targetDir = resolve(process.cwd(), targetName);
|
|
10
|
+
const templateArgIndex = args.indexOf('--template');
|
|
11
|
+
const templateName =
|
|
12
|
+
templateArgIndex !== -1 && args[templateArgIndex + 1] ? args[templateArgIndex + 1] : 'basic';
|
|
13
|
+
const templateRoot = resolve(fileURLToPath(new URL(`../templates/${templateName}`, import.meta.url)));
|
|
14
|
+
|
|
15
|
+
if (!existsSync(templateRoot)) {
|
|
16
|
+
console.error(`未知模板:${templateName}(可用:basic、ssr、admin)`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
11
19
|
|
|
12
20
|
if (existsSync(targetDir) && readdirSafe(targetDir).length > 0) {
|
|
13
21
|
console.error(`目标目录已存在且非空:${targetDir}`);
|
|
@@ -15,7 +23,7 @@ if (existsSync(targetDir) && readdirSafe(targetDir).length > 0) {
|
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
mkdirSync(targetDir, { recursive: true });
|
|
18
|
-
cpSync(
|
|
26
|
+
cpSync(templateRoot, targetDir, { recursive: true });
|
|
19
27
|
|
|
20
28
|
// 把模板 package.json 的 name 改为目标目录名
|
|
21
29
|
const packagePath = join(targetDir, 'package.json');
|
|
@@ -26,8 +34,16 @@ writeFileSync(packagePath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
|
26
34
|
console.log(`\n已创建 yoya-ui 项目:${targetName}\n`);
|
|
27
35
|
console.log(` cd ${targetName}`);
|
|
28
36
|
console.log(' npm install');
|
|
29
|
-
|
|
30
|
-
console.log('
|
|
37
|
+
if (templateName === 'ssr') {
|
|
38
|
+
console.log(' npm run build');
|
|
39
|
+
console.log(' npm start');
|
|
40
|
+
console.log('\nSSR 模板:renderPage 整页渲染 + hydrateOrMount 客户端接入。\n');
|
|
41
|
+
} else {
|
|
42
|
+
console.log(' npm run dev');
|
|
43
|
+
console.log(
|
|
44
|
+
`\n${templateName === 'admin' ? '管理后台模板:顶部导航 + 可折叠侧栏 + RouterViews 内容区。' : ''}更多:npm run build 构建,npm run preview 预览产物。\n`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
31
47
|
|
|
32
48
|
function sanitizeName(name) {
|
|
33
49
|
return name
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-yoya-ui",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Scaffold a new yoya-ui project with Vite:
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Scaffold a new yoya-ui project with Vite: basic template (SPA) or SSR template (renderPage + hydrateOrMount).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-yoya-ui": "bin/create-yoya-ui.js"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# yoya-ui 后台管理模板
|
|
2
|
+
|
|
3
|
+
标准管理后台布局:
|
|
4
|
+
|
|
5
|
+
- 左上角:logo + 系统名
|
|
6
|
+
- 中间:顶级导航
|
|
7
|
+
- 右上角:用户头像
|
|
8
|
+
- 下方:左侧可折叠菜单 + 右侧带标题的 RouterViews 内容区
|
|
9
|
+
- 点击顶级导航切换左侧菜单与内容路由
|
|
10
|
+
|
|
11
|
+
## 启动
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install
|
|
15
|
+
npm run dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 结构
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
src/
|
|
22
|
+
main.js 管理台壳:模块配置、路由、顶部导航、侧栏切换、内容区
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
扩展新模块:在 `main.js` 的 `modules` 数组里加一组 `{ key, label, icon, routes }` 即可。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>yoya-ui 管理台</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<main id="app"></main>
|
|
10
|
+
<script type="module" src="/src/main.js"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "yoya-ui-admin-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@yoyaflow/yoya-ui": "^0.2.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"vite": "^8.2.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createRouter,
|
|
3
|
+
toast,
|
|
4
|
+
vBody,
|
|
5
|
+
vNavbar,
|
|
6
|
+
vRouterViews,
|
|
7
|
+
vSidebar,
|
|
8
|
+
vstack
|
|
9
|
+
} from '@yoyaflow/yoya-ui';
|
|
10
|
+
import '@yoyaflow/yoya-ui/ui.css';
|
|
11
|
+
|
|
12
|
+
// ---------- 页面视图 ----------
|
|
13
|
+
|
|
14
|
+
function pageView(title, text) {
|
|
15
|
+
return vstack({ gap: '16px' }, (stack) => {
|
|
16
|
+
stack.h2(title);
|
|
17
|
+
stack.vCard((card) => {
|
|
18
|
+
card.vCardHeader(title);
|
|
19
|
+
card.vCardBody((body) => {
|
|
20
|
+
body.p(text);
|
|
21
|
+
body.vButton('操作', (btn) => {
|
|
22
|
+
btn.variant('primary');
|
|
23
|
+
btn.on('click', () => toast.success(`${title} 操作成功`));
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ---------- 模块配置:顶级导航 → 左侧菜单 → 路由 ----------
|
|
31
|
+
|
|
32
|
+
const modules = [
|
|
33
|
+
{
|
|
34
|
+
key: 'dashboard',
|
|
35
|
+
label: '工作台',
|
|
36
|
+
icon: 'D',
|
|
37
|
+
routes: [
|
|
38
|
+
{ path: '/dashboard/overview', title: '数据概览', text: '关键指标、趋势与告警一览。' },
|
|
39
|
+
{ path: '/dashboard/todos', title: '待办审批', text: '待处理审批与任务。' }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: 'ops',
|
|
44
|
+
label: '运维',
|
|
45
|
+
icon: 'O',
|
|
46
|
+
routes: [
|
|
47
|
+
{ path: '/ops/services', title: '服务清单', text: '服务列表与健康状态。' },
|
|
48
|
+
{ path: '/ops/deploys', title: '部署任务', text: '发布记录与执行状态。' }
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: 'system',
|
|
53
|
+
label: '系统',
|
|
54
|
+
icon: 'S',
|
|
55
|
+
routes: [
|
|
56
|
+
{ path: '/system/users', title: '成员管理', text: '成员列表与角色分配。' },
|
|
57
|
+
{ path: '/system/roles', title: '权限策略', text: '角色与权限规则。' }
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// ---------- 路由与内容区 ----------
|
|
63
|
+
|
|
64
|
+
const appRouter = createRouter((r) => {
|
|
65
|
+
modules.forEach((module) => {
|
|
66
|
+
module.routes.forEach((route) => {
|
|
67
|
+
r.route(route.path, { title: route.title, view: () => pageView(route.title, route.text) });
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
r.notFound(() => pageView('未找到', '该页面不存在。'));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ---------- 左侧菜单:随顶级导航切换 ----------
|
|
74
|
+
|
|
75
|
+
let activeTopItem = null;
|
|
76
|
+
|
|
77
|
+
function renderSidebarMenu(module) {
|
|
78
|
+
sidebar.menuContent((menu) => {
|
|
79
|
+
menu.vMenuGroup((group) => {
|
|
80
|
+
group.label(module.label);
|
|
81
|
+
module.routes.forEach((route) => {
|
|
82
|
+
group.vMenuItem((item) => {
|
|
83
|
+
item.icon(module.icon);
|
|
84
|
+
item.text(route.title);
|
|
85
|
+
item.on('click', () => appRouter.navigate(route.path));
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function switchModule(module, topItem) {
|
|
93
|
+
if (activeTopItem) {
|
|
94
|
+
activeTopItem.active(false);
|
|
95
|
+
}
|
|
96
|
+
activeTopItem = topItem;
|
|
97
|
+
topItem.active(true);
|
|
98
|
+
renderSidebarMenu(module);
|
|
99
|
+
appRouter.navigate(module.routes[0].path);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const sidebar = vSidebar((side) => {
|
|
103
|
+
side.ariaLabel('左侧菜单');
|
|
104
|
+
side.title('导航');
|
|
105
|
+
});
|
|
106
|
+
renderSidebarMenu(modules[0]);
|
|
107
|
+
|
|
108
|
+
// ---------- 顶部导航:logo + 系统名 / 顶级导航 / 用户头像 ----------
|
|
109
|
+
|
|
110
|
+
const navbar = vNavbar((nav) => {
|
|
111
|
+
nav.sticky(true);
|
|
112
|
+
nav.brand((brand) => {
|
|
113
|
+
brand.hstack({ gap: '8px' }, (row) => {
|
|
114
|
+
row.style('alignItems', 'center');
|
|
115
|
+
row.span((logo) => {
|
|
116
|
+
logo.style({
|
|
117
|
+
color: 'var(--yoya-color-primary, #2563eb)',
|
|
118
|
+
fontSize: '18px',
|
|
119
|
+
fontWeight: '700'
|
|
120
|
+
});
|
|
121
|
+
logo.text('◆');
|
|
122
|
+
});
|
|
123
|
+
row.strong('yoya 管理台');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
nav.menuContent((menu) => {
|
|
127
|
+
modules.forEach((module) => {
|
|
128
|
+
menu.vMenuItem((item) => {
|
|
129
|
+
item.text(module.label);
|
|
130
|
+
item.on('click', () => switchModule(module, item));
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
nav.actions((actions) => {
|
|
135
|
+
actions.vAvatar({ color: '#2563eb', size: 'small', text: '管' });
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// ---------- 页面壳:上方导航,下方左菜单右内容 ----------
|
|
140
|
+
|
|
141
|
+
const page = vBody((shell) => {
|
|
142
|
+
shell.gap(0);
|
|
143
|
+
shell.maxWidth('100%');
|
|
144
|
+
shell.padding(0);
|
|
145
|
+
shell.vContainer((frame) => {
|
|
146
|
+
frame.style('minHeight', '100vh');
|
|
147
|
+
frame.vHeader({ height: 56 }, (header) => {
|
|
148
|
+
header.style('padding', '0');
|
|
149
|
+
header.child(navbar);
|
|
150
|
+
});
|
|
151
|
+
frame.vContainer((body) => {
|
|
152
|
+
body.vAside({ width: 220 }, (aside) => {
|
|
153
|
+
aside.style('padding', '12px');
|
|
154
|
+
aside.child(sidebar);
|
|
155
|
+
});
|
|
156
|
+
body.vMain((main) => {
|
|
157
|
+
main.style('padding', '16px');
|
|
158
|
+
main.child(vRouterViews(appRouter, { lockTitle: true, title: '内容区' }));
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
page.bindTo('#app');
|
|
165
|
+
appRouter.start();
|
|
166
|
+
appRouter.navigate(modules[0].routes[0].path, { replace: true }); // 进入默认模块首页
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# yoya-ui SSR 示例项目
|
|
2
|
+
|
|
3
|
+
基于 [yoya-ui](https://github.com/yoyaflow/yoya-ui) 的服务端渲染模板:
|
|
4
|
+
|
|
5
|
+
- 页面即组件:`HomePage(state)` 服务端与客户端共用
|
|
6
|
+
- 整页渲染:`renderPage({ page }, state, { messages })` 一行输出完整 HTML
|
|
7
|
+
- 客户端一行接入:`hydrateOrMount(HomePage, { messages })`
|
|
8
|
+
- 每请求 i18n:`messages` 按 `state.lang` 建实例,`.s()` 自动作用域
|
|
9
|
+
|
|
10
|
+
## 启动
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install
|
|
14
|
+
npm run build # 生成 dist/client.js 与 dist/assets/yoya.ui.css
|
|
15
|
+
npm start # http://localhost:3000
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 结构
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
src/
|
|
22
|
+
home-page.js 页面组件 + 词典(两端共用)
|
|
23
|
+
server.mjs node:http 服务端(renderPage 整页渲染 + 静态资源)
|
|
24
|
+
client.js 浏览器入口(hydrateOrMount)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
语言标识:切换语言时写 cookie(如 `document.cookie = 'yoya-lang=en; path=/'`),服务端从 cookie 解析 `lang` 传入 `renderPage`。
|
|
28
|
+
|
|
29
|
+
## 学习资源
|
|
30
|
+
|
|
31
|
+
- SSR 集成与底层原语(renderToString / hydrate / mount)见 [docs/ssr.md](https://github.com/yoyaflow/yoya-ui/blob/main/docs/ssr.md)
|
|
32
|
+
- 完整 API 见包内类型声明(`types/*.d.ts`)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "yoya-ui-ssr-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"start": "node src/server.mjs",
|
|
9
|
+
"preview": "npm run build && npm start"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@yoyaflow/yoya-ui": "^0.2.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"vite": "^8.2.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createRouter, div } from '@yoyaflow/yoya-ui/ssr';
|
|
2
|
+
|
|
3
|
+
export const messages = {
|
|
4
|
+
'zh-CN': { title: 'SSR 示例', home: '首页' },
|
|
5
|
+
'en-US': { title: 'SSR Demo', home: 'Home' }
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// 页面即形态 A 组件:服务端与客户端共用同一份定义
|
|
9
|
+
export function HomePage(state) {
|
|
10
|
+
const router = createRouter();
|
|
11
|
+
router.mode(state.mode || 'history');
|
|
12
|
+
router.route('/home', '首页'.s('home'));
|
|
13
|
+
router.notFound('未找到');
|
|
14
|
+
router.renderPath(state.path || '/home');
|
|
15
|
+
|
|
16
|
+
return div((root) => {
|
|
17
|
+
root.h1('SSR 示例'.s('title'));
|
|
18
|
+
root.child(router);
|
|
19
|
+
root.p('服务端渲染完成,事件由 hydrate 在浏览器端绑定。');
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { extname, join } from 'node:path';
|
|
4
|
+
import { renderPage } from '@yoyaflow/yoya-ui/ssr';
|
|
5
|
+
import { HomePage, messages } from './home-page.js';
|
|
6
|
+
|
|
7
|
+
const DIST = join(import.meta.dirname, '..', 'dist');
|
|
8
|
+
const MIME = { '.css': 'text/css', '.js': 'text/javascript' };
|
|
9
|
+
const PORT = Number(process.env.PORT || 3000);
|
|
10
|
+
|
|
11
|
+
createServer((req, res) => {
|
|
12
|
+
const path = new URL(req.url, 'http://localhost').pathname;
|
|
13
|
+
|
|
14
|
+
// 静态资源:client.js 与 assets/yoya.ui.css 由 npm run build 产出
|
|
15
|
+
if (path !== '/') {
|
|
16
|
+
const file = join(DIST, path.slice(1));
|
|
17
|
+
if (existsSync(file)) {
|
|
18
|
+
res.writeHead(200, { 'Content-Type': MIME[extname(file)] || 'application/octet-stream' });
|
|
19
|
+
res.end(readFileSync(file));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// lang 由你的服务端解析(cookie / query / 登录态都行)
|
|
25
|
+
const lang = req.headers.cookie?.includes('yoya-lang=en') ? 'en' : 'zh-CN';
|
|
26
|
+
|
|
27
|
+
const html = renderPage(
|
|
28
|
+
{
|
|
29
|
+
page: (page, state) => {
|
|
30
|
+
page.head((head) => {
|
|
31
|
+
head.title('SSR 示例'.s('title'));
|
|
32
|
+
head.meta({ charset: 'utf-8' });
|
|
33
|
+
head.link({ rel: 'stylesheet', href: '/assets/yoya.ui.css' });
|
|
34
|
+
});
|
|
35
|
+
page.body((body) => {
|
|
36
|
+
body.vBody((shell) => {
|
|
37
|
+
shell.child(HomePage(state)); // state = { lang, path, mode }
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{ lang, mode: 'history', path },
|
|
43
|
+
{ messages } // 按 state.lang 建每请求 i18n,.s() 自动作用域
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
47
|
+
res.end(html);
|
|
48
|
+
}).listen(PORT, () => console.log(`SSR server: http://localhost:${PORT}`));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
build: {
|
|
5
|
+
emptyOutDir: true,
|
|
6
|
+
outDir: 'dist',
|
|
7
|
+
rollupOptions: {
|
|
8
|
+
input: 'src/client.js',
|
|
9
|
+
output: {
|
|
10
|
+
assetFileNames: (assetInfo) =>
|
|
11
|
+
assetInfo.name?.endsWith('.css') ? 'assets/yoya.ui.css' : 'assets/[name][extname]',
|
|
12
|
+
entryFileNames: 'client.js'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
});
|