cdui-js 1.0.2 → 1.0.4
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 +0 -2
- package/build/icons.ts +8 -8
- package/package.json +5 -6
- package/src/components/Switch.tsx +1 -1
- package/src/index.ts +1 -31
- package/src/location.ts +3 -3
- package/src/reactive.ts +31 -1
- package/src/ssr/render.ts +178 -0
- package/src/ssr/window/index.ts +1 -0
- package/src/ssr/window/storage.ts +27 -0
- package/ssr-package.js +14 -0
- package/tsconfig.json +42 -0
- package/vite.config.ts +0 -35
package/README.md
CHANGED
package/build/icons.ts
CHANGED
|
@@ -2,12 +2,12 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* 从指定 svg
|
|
5
|
+
* 从指定 svg 文件加载 symbol 内容
|
|
6
6
|
*
|
|
7
7
|
* @param svgFile 指定 svg 文件
|
|
8
8
|
* @param removeColor 去色标记 fill: 去填充色 stroke:去描边色 both:都去
|
|
9
9
|
*/
|
|
10
|
-
export const
|
|
10
|
+
export const loadIconFile = (svgFile: string, removeColor?: 'fill' | 'stroke' | 'both'): string => {
|
|
11
11
|
let name = path.basename(svgFile).replace('.svg', '');
|
|
12
12
|
let svg = fs.readFileSync(svgFile, 'utf8');
|
|
13
13
|
let index = svg.indexOf(' viewBox="');
|
|
@@ -46,7 +46,7 @@ export const readIconFile = (svgFile: string, removeColor?: 'fill' | 'stroke' |
|
|
|
46
46
|
* @param svgDirectory 指定 svg 目录
|
|
47
47
|
* @param removeColor 去色标记 fill: 去填充色 stroke:去描边色 both:都去
|
|
48
48
|
*/
|
|
49
|
-
export const
|
|
49
|
+
export const loadIconsDirectory = (svgDirectory: string, removeColor?: 'fill' | 'stroke' | 'both'): string => {
|
|
50
50
|
const outputs = [];
|
|
51
51
|
const files = fs.readdirSync(svgDirectory);
|
|
52
52
|
|
|
@@ -54,7 +54,7 @@ export const readIconsDirectory = (svgDirectory: string, removeColor?: 'fill' |
|
|
|
54
54
|
let file = path.join(svgDirectory, files[i]);
|
|
55
55
|
|
|
56
56
|
if (path.extname(file) === '.svg') {
|
|
57
|
-
outputs.push(
|
|
57
|
+
outputs.push(loadIconFile(file, removeColor));
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -62,12 +62,12 @@ export const readIconsDirectory = (svgDirectory: string, removeColor?: 'fill' |
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* 把图标 symbol
|
|
65
|
+
* 把图标 symbol 内容保存到 html 文件中
|
|
66
66
|
*
|
|
67
67
|
* @param htmlFile html 文件路径
|
|
68
68
|
* @param symbols 图标 symbol 集合
|
|
69
69
|
*/
|
|
70
|
-
export const
|
|
70
|
+
export const saveIconsToHtml = (htmlFile: string, symbols: string) => {
|
|
71
71
|
let html = fs.readFileSync(htmlFile, 'utf8');
|
|
72
72
|
let index = html.indexOf('<svg id="ICONS" ');
|
|
73
73
|
|
|
@@ -91,12 +91,12 @@ export const writeIconsToHtml = (htmlFile: string, symbols: string) => {
|
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
*
|
|
94
|
+
* 把 svg 图标保存到模块文件中
|
|
95
95
|
*
|
|
96
96
|
* @param moduleFile 模块文件名
|
|
97
97
|
* @param symbols svg 图标内容
|
|
98
98
|
*/
|
|
99
|
-
export const
|
|
99
|
+
export const saveIconsModule = (moduleFile: string, symbols: string) => {
|
|
100
100
|
fs.writeFileSync(
|
|
101
101
|
moduleFile,
|
|
102
102
|
`import { loadSvgIcons } from 'cdui-js';
|
package/package.json
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdui-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cdui-js": "./cli/bin.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"dev": "vite --config vite.config.ts",
|
|
11
|
-
"build": "vite build --config vite.config.ts"
|
|
12
10
|
},
|
|
13
11
|
"dependencies": {
|
|
12
|
+
"chalk": "^5.6.2",
|
|
14
13
|
"commander": "^14.0.3",
|
|
15
|
-
"inquirer": "^13.3.0",
|
|
16
14
|
"download-git-repo": "^3.0.2",
|
|
17
|
-
"chalk": "^5.6.2",
|
|
18
15
|
"fs-extra": "^11.3.3",
|
|
16
|
+
"inquirer": "^13.3.0",
|
|
19
17
|
"solid-js": "^1.9.10",
|
|
20
18
|
"vite-plugin-solid": "^2.11.10"
|
|
21
19
|
},
|
|
22
20
|
"devDependencies": {
|
|
21
|
+
"@types/node": "^25.3.3",
|
|
23
22
|
"typescript": "~5.6.2"
|
|
24
23
|
}
|
|
25
|
-
}
|
|
24
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -35,34 +35,4 @@ export * from './components/Carousel';
|
|
|
35
35
|
export * from './components/KeepAlive';
|
|
36
36
|
export * from './components/Dialog';
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
export interface ImportMeta {
|
|
40
|
-
// 配置环境变量类型
|
|
41
|
-
env: {
|
|
42
|
-
/**
|
|
43
|
-
* 应用运行模式
|
|
44
|
-
*/
|
|
45
|
-
MODE: string;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* 是否服务端渲染
|
|
49
|
-
*/
|
|
50
|
-
SSR: boolean;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* 是否浏览器模式
|
|
54
|
-
*/
|
|
55
|
-
VITE_BROWSER: boolean;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* API基础路径
|
|
59
|
-
*/
|
|
60
|
-
VITE_API_BASE_URL: string;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 是否开启 API Mock
|
|
64
|
-
*/
|
|
65
|
-
VITE_API_MOCK: boolean;
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
38
|
+
export * from './ssr/render';
|
package/src/location.ts
CHANGED
|
@@ -62,7 +62,7 @@ export const location: Location = reactive({
|
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
export const parseQuery = (search: string) => {
|
|
65
|
-
let query = {};
|
|
65
|
+
let query: any = {};
|
|
66
66
|
let items = search.slice(1).split('&');
|
|
67
67
|
let item;
|
|
68
68
|
|
|
@@ -95,12 +95,12 @@ export const parseQuery = (search: string) => {
|
|
|
95
95
|
*/
|
|
96
96
|
export const updateURL = (path: string, search?: string, hash?: string) => {
|
|
97
97
|
location.url = path + (search || '') + (hash || '');
|
|
98
|
-
location.hash = hash;
|
|
98
|
+
location.hash = hash || '';
|
|
99
99
|
|
|
100
100
|
if (location.path !== path || location.search !== search) {
|
|
101
101
|
location.path = path;
|
|
102
102
|
location.paths = path.match(/\/[^/]*/g) || [];
|
|
103
|
-
location.search = search;
|
|
103
|
+
location.search = search || '';
|
|
104
104
|
location.query = search ? parseQuery(search) : {};
|
|
105
105
|
}
|
|
106
106
|
};
|
package/src/reactive.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface ServerContext {
|
|
|
8
8
|
/**
|
|
9
9
|
* 异步等待集合
|
|
10
10
|
*/
|
|
11
|
-
promises:
|
|
11
|
+
promises: any[];
|
|
12
12
|
/**
|
|
13
13
|
* 已经获取的异步缓存
|
|
14
14
|
*/
|
|
@@ -33,6 +33,36 @@ export const setServerContext = (context: ServerContext) => {
|
|
|
33
33
|
serverContext = context;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* 服务端渲染页面配置
|
|
38
|
+
*/
|
|
39
|
+
export interface SSRRenderPage {
|
|
40
|
+
/**
|
|
41
|
+
* 页面路径
|
|
42
|
+
*/
|
|
43
|
+
path: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 搜索
|
|
47
|
+
*/
|
|
48
|
+
search?: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 页面 title 集合,(key 为语言代码)
|
|
52
|
+
*/
|
|
53
|
+
title?: string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 页面描述集合,(key 为语言代码)
|
|
57
|
+
*/
|
|
58
|
+
description?: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 出现异常时是否终止渲染(渲染终止)
|
|
62
|
+
*/
|
|
63
|
+
abort?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
36
66
|
class ReactiveArray {}
|
|
37
67
|
|
|
38
68
|
/**
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
export type { SSRRenderPage } from '../reactive';
|
|
2
|
+
|
|
3
|
+
// 预先加载 window 补丁
|
|
4
|
+
import './window';
|
|
5
|
+
|
|
6
|
+
import path from 'path';
|
|
7
|
+
// fs/promises 不稳定,有时会出现异步错误无法捕获的异步
|
|
8
|
+
import fs, { PathLike, PathOrFileDescriptor, WriteFileOptions } from 'fs';
|
|
9
|
+
|
|
10
|
+
import { Component, createComponent } from 'solid-js';
|
|
11
|
+
import { generateHydrationScript, renderToString } from 'solid-js/web';
|
|
12
|
+
|
|
13
|
+
import { updateURL } from '../location';
|
|
14
|
+
import { SSRRenderPage, ServerContext, setServerContext } from '../reactive';
|
|
15
|
+
|
|
16
|
+
const exists = (path: PathLike): Promise<boolean> => {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
fs.stat(path, (err, stats) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
resolve(false);
|
|
21
|
+
} else {
|
|
22
|
+
resolve(true);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const mkdir = (path: PathLike) => {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
fs.mkdir(path, { recursive: true }, (err) => {
|
|
31
|
+
if (err) {
|
|
32
|
+
reject(err);
|
|
33
|
+
} else {
|
|
34
|
+
resolve(void 0);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const writeFile = (path: PathOrFileDescriptor, data: string | DataView, options: WriteFileOptions): Promise<void> => {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
fs.writeFile(path, data, options, (err) => {
|
|
43
|
+
if (err) {
|
|
44
|
+
reject(err);
|
|
45
|
+
} else {
|
|
46
|
+
resolve(void 0);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const renderToStringAsync = async <T>(context: ServerContext, fn: () => T) => {
|
|
53
|
+
while (true) {
|
|
54
|
+
setServerContext(context);
|
|
55
|
+
|
|
56
|
+
let html = renderToString(fn);
|
|
57
|
+
|
|
58
|
+
if (context.promises[0]) {
|
|
59
|
+
await Promise.all(context.promises);
|
|
60
|
+
context.promises.length = 0;
|
|
61
|
+
} else {
|
|
62
|
+
return html;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 渲染单个页面
|
|
69
|
+
*/
|
|
70
|
+
const renderPage = async (
|
|
71
|
+
App: Component<any>,
|
|
72
|
+
languages: { [key: string]: any },
|
|
73
|
+
language: string,
|
|
74
|
+
root: string,
|
|
75
|
+
template: string,
|
|
76
|
+
page: SSRRenderPage,
|
|
77
|
+
) => {
|
|
78
|
+
let context = { promises: [], cache: new Map(), ssr: {} };
|
|
79
|
+
let title = page.title;
|
|
80
|
+
let description = page.description;
|
|
81
|
+
let scripts = [];
|
|
82
|
+
|
|
83
|
+
// 设置当前路由路径
|
|
84
|
+
updateURL(page.path, page.search);
|
|
85
|
+
|
|
86
|
+
// 渲染html
|
|
87
|
+
let html = await renderToStringAsync(context, () => createComponent(App, null));
|
|
88
|
+
|
|
89
|
+
// 多语言
|
|
90
|
+
if (language !== 'en') {
|
|
91
|
+
template = template.replace('lang="en"', 'lang="' + language + '"');
|
|
92
|
+
|
|
93
|
+
if (languages[language]) {
|
|
94
|
+
scripts.push('<script type="text/javascript">window.I18N=' + JSON.stringify(languages[language]) + '</script>');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (Object.getOwnPropertyNames(context.ssr).length > 0) {
|
|
99
|
+
scripts.push('<script type="text/javascript">window.SSR=' + JSON.stringify(context.ssr) + '</script>');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
scripts.push(generateHydrationScript());
|
|
103
|
+
|
|
104
|
+
// 插入内容
|
|
105
|
+
html = template.replace('<!-- ssr-body -->', html);
|
|
106
|
+
|
|
107
|
+
// 插入头部脚本
|
|
108
|
+
html = html.replace('<!-- ssr-head -->', scripts.join(''));
|
|
109
|
+
|
|
110
|
+
if (title) {
|
|
111
|
+
html = html.replace(/\<title\>[^<]+/, '<title>' + title);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (description) {
|
|
115
|
+
html = html.replace(
|
|
116
|
+
/\<meta\s+name\=\"description\"\s+content\=\"[^"]+/,
|
|
117
|
+
'<meta name="description" content="' + description,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let file = path.join(root, 'ssr', language, page.path);
|
|
122
|
+
let dir = path.dirname(file);
|
|
123
|
+
|
|
124
|
+
if (!(await exists(dir))) {
|
|
125
|
+
await mkdir(dir);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
await writeFile(file, html, 'utf8');
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 服务端渲染错误集合
|
|
133
|
+
*/
|
|
134
|
+
export const SSR_ERRORS = [];
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 渲染服务端页面集合
|
|
138
|
+
*/
|
|
139
|
+
export const renderSSRPages = async (
|
|
140
|
+
App: Component<any>,
|
|
141
|
+
languages: { [key: string]: any },
|
|
142
|
+
language: string,
|
|
143
|
+
root: string,
|
|
144
|
+
template: string,
|
|
145
|
+
pages: SSRRenderPage[],
|
|
146
|
+
) => {
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
if (import.meta.env.SSR) {
|
|
149
|
+
for (let i = 0, l = pages.length; i < l; i++) {
|
|
150
|
+
let page = pages[i];
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
let now = Date.now();
|
|
154
|
+
|
|
155
|
+
console.log(`rendering:${language} ${page.path}`);
|
|
156
|
+
|
|
157
|
+
await renderPage(App, languages, language, root, template, page);
|
|
158
|
+
|
|
159
|
+
console.log(`rendered: ${language} ${page.path} time: ${Date.now() - now}`);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
console.error(err);
|
|
162
|
+
SSR_ERRORS.push(err.message + ': ' + (err.cause || { message: '...' }).message);
|
|
163
|
+
|
|
164
|
+
// 页面渲染失败终止渲染
|
|
165
|
+
if (page.abort) {
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (SSR_ERRORS[0]) {
|
|
172
|
+
return Promise.reject({
|
|
173
|
+
language,
|
|
174
|
+
errors: SSR_ERRORS,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './storage';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
if (import.meta.env.SSR) {
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
const localStorage = new Map();
|
|
5
|
+
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
global.localStorage = global.sessionStorage = {
|
|
8
|
+
get length() {
|
|
9
|
+
return localStorage.size;
|
|
10
|
+
},
|
|
11
|
+
key(index) {
|
|
12
|
+
return localStorage.keys()[index];
|
|
13
|
+
},
|
|
14
|
+
getItem(key) {
|
|
15
|
+
return localStorage.get(key) || '';
|
|
16
|
+
},
|
|
17
|
+
setItem(key, value) {
|
|
18
|
+
localStorage.set('' + key, '' + value);
|
|
19
|
+
},
|
|
20
|
+
removeItem(key) {
|
|
21
|
+
localStorage.delete(key);
|
|
22
|
+
},
|
|
23
|
+
clear() {
|
|
24
|
+
localStorage.clear();
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
package/ssr-package.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const SSRPackageJSON = JSON.stringify({
|
|
2
|
+
name: '@cdui-js/ssr',
|
|
3
|
+
private: true,
|
|
4
|
+
version: '0.0.0',
|
|
5
|
+
type: 'module',
|
|
6
|
+
main: 'server.js',
|
|
7
|
+
devDependencies: {
|
|
8
|
+
express: '^4.21.2',
|
|
9
|
+
commander: '^12.1.0',
|
|
10
|
+
'html-minifier': '^4.0.0',
|
|
11
|
+
'solid-js': '^1.9.10',
|
|
12
|
+
},
|
|
13
|
+
dependencies: {},
|
|
14
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @link https://www.typescriptlang.org/tsconfig
|
|
3
|
+
* @link https://cn.vuejs.org/guide/typescript/overview#configuring-tsconfig-json
|
|
4
|
+
* @link https://cn.vite.dev/guide/features#typescript-compiler-options
|
|
5
|
+
*/
|
|
6
|
+
{
|
|
7
|
+
"compilerOptions": {
|
|
8
|
+
"target": "esnext",
|
|
9
|
+
"jsx": "preserve",
|
|
10
|
+
"jsxImportSource": "solid-js",
|
|
11
|
+
// "jsxFactory": "h",
|
|
12
|
+
// "jsxFragmentFactory": "Fragment",
|
|
13
|
+
"lib": [
|
|
14
|
+
"esnext",
|
|
15
|
+
"dom"
|
|
16
|
+
],
|
|
17
|
+
"useDefineForClassFields": true,
|
|
18
|
+
"experimentalDecorators": true,
|
|
19
|
+
// baseUrl 用来告诉编译器到哪里去查找模块,使用非相对模块时必须配置此项
|
|
20
|
+
"baseUrl": ".",
|
|
21
|
+
"module": "esnext",
|
|
22
|
+
"moduleResolution": "bundler",
|
|
23
|
+
// 非相对模块导入的路径映射配置,根据 baseUrl 配置进行路径计算,与 vite.config 中 alias 配置同步
|
|
24
|
+
"paths": {},
|
|
25
|
+
"resolveJsonModule": true,
|
|
26
|
+
"types": [],
|
|
27
|
+
// 允许导入 .ts .mts .tsx 拓展名的文件
|
|
28
|
+
"allowImportingTsExtensions": true,
|
|
29
|
+
// 允许 JS
|
|
30
|
+
// "allowJs": true,
|
|
31
|
+
// TS 严格模式
|
|
32
|
+
// "strict": true,
|
|
33
|
+
"importHelpers": true,
|
|
34
|
+
// 不输出任何编译后的文件,只进行类型检查
|
|
35
|
+
"noEmit": true,
|
|
36
|
+
"sourceMap": true,
|
|
37
|
+
"allowSyntheticDefaultImports": true,
|
|
38
|
+
"esModuleInterop": true,
|
|
39
|
+
"isolatedModules": true,
|
|
40
|
+
"skipLibCheck": true
|
|
41
|
+
}
|
|
42
|
+
}
|
package/vite.config.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import { fileURLToPath } from 'url';
|
|
3
|
-
import { defineConfig } from 'vite';
|
|
4
|
-
|
|
5
|
-
import VitePlugin from 'vite-plugin-solid';
|
|
6
|
-
|
|
7
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
-
const __dirname = path.dirname(__filename);
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* h5构建方法
|
|
12
|
-
*/
|
|
13
|
-
export default defineConfig({
|
|
14
|
-
root: __dirname,
|
|
15
|
-
base: '/',
|
|
16
|
-
plugins: [
|
|
17
|
-
VitePlugin({})
|
|
18
|
-
],
|
|
19
|
-
build: {
|
|
20
|
-
// target: 'es2015',
|
|
21
|
-
modulePreload: false,
|
|
22
|
-
outDir: path.join(__dirname, 'dist'),
|
|
23
|
-
emptyOutDir: true,
|
|
24
|
-
rollupOptions: {
|
|
25
|
-
input: path.join(__dirname, 'index.html'),
|
|
26
|
-
output: {
|
|
27
|
-
entryFileNames: 'js/[name]-[hash].js',
|
|
28
|
-
chunkFileNames: 'js/[name]-[hash].js',
|
|
29
|
-
assetFileNames: '[ext]/[name]-[hash].[ext]',
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
minify: false,
|
|
33
|
-
sourcemap: true,
|
|
34
|
-
}
|
|
35
|
-
});
|