coda-builder 0.0.0-stage → 1.0.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.md +279 -2
- package/package.json +51 -4
package/README.md
CHANGED
|
@@ -1,3 +1,280 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Coda-Builder
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`Coda-Builder` 是一个专为 TypeScript 多平台打造的现代化 Webpack 封装与标准化构建工具。旨在以极低的配置开销,统一管理和输出多平台项目(Node CLI、Node Server、VS Code 扩展、Chrome 扩展、Web等)
|
|
4
|
+
|
|
5
|
+
## 🌟 核心特性
|
|
6
|
+
|
|
7
|
+
1. **全面支持**:支持 Web、Node.js 命令行、Node.js 服务端、VS Code 插件以及 Chrome 扩展等多平台环境的无缝构建与差异化适配。
|
|
8
|
+
|
|
9
|
+
2. **开箱即用**:提供极简的最小配置支持,内置了常用的 TypeScript 编译、样式加载、静态资源处理及 HTML 模板自动注入能力。
|
|
10
|
+
|
|
11
|
+
3. **最佳性能**:内置企业级实践最佳性能配置,支持 Gzip 压缩、Terser 与 CSS 压缩优化、多线程编译(thread-loader)以及智能代码切片。
|
|
12
|
+
|
|
13
|
+
4. **自由扩展**:完美兼容 Webpack 原生属性与丰富的自定义快捷属性,并严格遵循“Webpack 原生属性优先”的合并策略。
|
|
14
|
+
|
|
15
|
+
5. **高度可控**:提供内置的高级钩子函数(configureWebpack),在享受自动化便利的同时保留绝对的控制权。
|
|
16
|
+
|
|
17
|
+
## 📦 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm i coda-builder --dev-save
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 🛠 配置接口说明 (CodaUserConfig)
|
|
24
|
+
|
|
25
|
+
| 参数名 | 类型 | 默认值 | 说明 |
|
|
26
|
+
| :--------------- | :------------------------------------------------------------------------------- | :-------------------- | :-------------------------------------------------------------------------------------------- |
|
|
27
|
+
| techRoute | TechRoute | - (必填) | 适配的技术路线 ('typescript' \| 'web') |
|
|
28
|
+
| platformTarget | PlatformTarget | - (必填) | 多平台构建和开发目标 ('nodejs-cli' \| 'node-server' \| 'chrome-ext' \| 'vscode-ext' \| 'web') |
|
|
29
|
+
| mode | BuildMode | - (必填) | Webpack 运行模式 ('production' \| 'development' \| 'analyzer') |
|
|
30
|
+
| entry | WebpackConfiguration['entry'] | - (必填) | 脚本入口配置 |
|
|
31
|
+
| context | WebpackConfiguration['context'] | process.cwd() | 命令执行上下文绝对路径 |
|
|
32
|
+
| output | WebpackConfiguration['output'] | undefined | 构建产物输出配置 |
|
|
33
|
+
| module | WebpackConfiguration['module'] | undefined | 模块匹配与解析规则 (原生优先) |
|
|
34
|
+
| resolve | WebpackConfiguration['resolve'] | undefined | 模块解析配置 (原生优先) |
|
|
35
|
+
| optimization | WebpackConfiguration['optimization'] | undefined | 代码优化与分包配置 |
|
|
36
|
+
| plugins | WebpackConfiguration['plugins'] | undefined | 自定义 Webpack 插件列表 |
|
|
37
|
+
| devServer | DevServerConfiguration | undefined | 开发服务器配置 |
|
|
38
|
+
| cache | WebpackConfiguration['cache'] | undefined | 构建缓存配置 |
|
|
39
|
+
| devtool | WebpackConfiguration['devtool'] | undefined | Source Map 生成方式 |
|
|
40
|
+
| target | WebpackConfiguration['target'] | 自动适配 | 编译目标环境 |
|
|
41
|
+
| watch | WebpackConfiguration['watch'] | undefined | 是否开启文件增量监听 |
|
|
42
|
+
| watchOptions | WebpackConfiguration['watchOptions'] | undefined | 文件监听选项 |
|
|
43
|
+
| externals | WebpackConfiguration['externals'] | 平台内置处理 | 外部依赖处理 |
|
|
44
|
+
| stats | WebpackConfiguration['stats'] | undefined | 构建日志输出控制 |
|
|
45
|
+
| noParse | NonNullable<WebpackConfiguration['module']>['noParse'] | undefined | 不需要解析的第三方大文件正则或数组 |
|
|
46
|
+
| rules | NonNullable<WebpackConfiguration['module']>['rules'] | undefined | 资源加载器规则 (自动映射至 Webpack module.rules) |
|
|
47
|
+
| alias | Record<string, string> | undefined | 模块路径别名(快捷属性,映射至 resolve.alias) |
|
|
48
|
+
| extensions | string[] | ['.ts', '.js'] | 模块解析扩展名列表(快捷属性) |
|
|
49
|
+
| extensionAlias | Record<string, string \| string[]> | undefined | 文件后缀别名映射 |
|
|
50
|
+
| modules | NonNullable<WebpackConfiguration['resolve']>['modules'] | ['node_modules'] | 模块解析查找目录 |
|
|
51
|
+
| mainFields | NonNullable<WebpackConfiguration['resolve']>['mainFields'] | undefined | 依赖包主文件字段 |
|
|
52
|
+
| maxChunks | number | undefined | 限制每个入口生成的最大 Chunk 数量 |
|
|
53
|
+
| splitChunks | WebpackConfiguration['optimization'] extends {splitChunks?: infer S} ? S : never | 智能适配 | 代码切片配置 (继承 Webpack optimization.splitChunks) |
|
|
54
|
+
| minimize | boolean | 生产/分析模式默认开启 | 是否启用代码压缩 minimization |
|
|
55
|
+
| terserOptions | TerserPlugin['options'] | 内置优化配置 | Terser 脚本压缩优化选项 (基于 terser-webpack-plugin) |
|
|
56
|
+
| parallel | number | undefined | 压缩插件启用的 CPU 核心数 (基于 terser-webpack-plugin) |
|
|
57
|
+
| speedMeasure | boolean | false | 是否开启构建打包测速 (基于 speed-measure-webpack-v5-plugin) |
|
|
58
|
+
| thread | boolean | false | 是否开启多线程编译 thread-loader |
|
|
59
|
+
| workerOptions | WorkerOptions | 默认自适应核数 | thread-loader 的自定义 Worker 选项 |
|
|
60
|
+
| html | HtmlWebpackPluginOptions \| boolean | undefined | HTML 模板注入配置 (基于 html-webpack-plugin) |
|
|
61
|
+
| copyRules | CopyRuleItem[] | undefined | 静态资源复制与模板处理规则 |
|
|
62
|
+
| gzip | CompressionPlugin['options'] \| boolean | 生产/分析模式默认开启 | Gzip 压缩配置 (基于 compression-webpack-plugin) |
|
|
63
|
+
| configureWebpack | (config, mode) => WebpackConfiguration \| void | undefined | 高级扩展钩子函数(终极逃生舱) |
|
|
64
|
+
|
|
65
|
+
## 🚀 使用指南
|
|
66
|
+
|
|
67
|
+
在你的业务项目根目录下创建 webpack.config.ts:
|
|
68
|
+
|
|
69
|
+
1. node服务 配置示例
|
|
70
|
+
|
|
71
|
+
```TypeScript
|
|
72
|
+
import * as path from 'path';
|
|
73
|
+
import type {Configuration} from 'webpack';
|
|
74
|
+
import {resolveWebpackConfig, CodaUserConfig} from 'coda-builder';
|
|
75
|
+
|
|
76
|
+
const config: CodaUserConfig = {
|
|
77
|
+
platformTarget: 'node-server',
|
|
78
|
+
techRoute: 'typescript',
|
|
79
|
+
mode: 'production',
|
|
80
|
+
entry: './src/main.ts',
|
|
81
|
+
output: {
|
|
82
|
+
filename: 'main.js',
|
|
83
|
+
path: path.resolve(__dirname, 'dist'),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const webpackConfig: Configuration = resolveWebpackConfig(config);
|
|
88
|
+
|
|
89
|
+
export default webpackConfig;
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
2. node命令行工具 配置示例
|
|
93
|
+
|
|
94
|
+
```TypeScript
|
|
95
|
+
import * as path from 'path';
|
|
96
|
+
import * as fs from 'fs';
|
|
97
|
+
import type {Configuration} from 'webpack';
|
|
98
|
+
import {resolveWebpackConfig, CodaUserConfig} from 'coda-builder';
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 递归扫描 src 目录,自动获取所有 index.ts 作为入口
|
|
102
|
+
*/
|
|
103
|
+
function getEntries(srcDir: string) {
|
|
104
|
+
let entries: Record<string, string> = {};
|
|
105
|
+
|
|
106
|
+
function scan(dir: string) {
|
|
107
|
+
const files = fs.readdirSync(dir, {withFileTypes: true});
|
|
108
|
+
files.forEach(file => {
|
|
109
|
+
const fullPath = path.join(dir, file.name);
|
|
110
|
+
if (file.isDirectory()) {
|
|
111
|
+
if (file.name !== 'tmpl' && file.name !== 'templates') {
|
|
112
|
+
scan(fullPath);
|
|
113
|
+
}
|
|
114
|
+
} else if (file.name === 'index.ts' || file.name === 'index.js') {
|
|
115
|
+
const relativePath = path.relative(srcDir, fullPath);
|
|
116
|
+
const entryKey = relativePath.replace(/\\/g, '/').replace(/\.tsx?$/, '');
|
|
117
|
+
entries[entryKey] = fullPath;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
scan(srcDir);
|
|
123
|
+
return entries;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const srcPath = path.resolve(__dirname, 'src');
|
|
127
|
+
|
|
128
|
+
const config: CodaUserConfig = {
|
|
129
|
+
techRoute: 'typescript',
|
|
130
|
+
platformTarget: 'nodejs-cli',
|
|
131
|
+
entry: getEntries(srcPath),
|
|
132
|
+
mode: 'development',
|
|
133
|
+
output: {
|
|
134
|
+
path: path.resolve(__dirname, 'dist'),
|
|
135
|
+
},
|
|
136
|
+
maxChunks: 1,
|
|
137
|
+
alias: {
|
|
138
|
+
'@': path.resolve(__dirname, 'src'),
|
|
139
|
+
},
|
|
140
|
+
extensionAlias: {
|
|
141
|
+
'.js': ['.ts', '.js'],
|
|
142
|
+
'.ts': ['.ts', '.js'],
|
|
143
|
+
},
|
|
144
|
+
copyRules: [
|
|
145
|
+
// 复制根目录基础文件
|
|
146
|
+
{
|
|
147
|
+
type: 'single',
|
|
148
|
+
from: path.resolve(__dirname, 'package.json'),
|
|
149
|
+
to: 'package.json',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: 'single',
|
|
153
|
+
from: path.resolve(__dirname, 'README.md'),
|
|
154
|
+
to: 'README.md',
|
|
155
|
+
},
|
|
156
|
+
// 复制目录
|
|
157
|
+
{
|
|
158
|
+
type: 'directory',
|
|
159
|
+
from: path.resolve(__dirname, 'src', 'config'),
|
|
160
|
+
to: 'config',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'directory',
|
|
164
|
+
from: path.resolve(__dirname, 'src', 'service'),
|
|
165
|
+
to: 'service',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
type: 'directory',
|
|
169
|
+
from: path.resolve(__dirname, 'templates'),
|
|
170
|
+
to: 'templates',
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const webpackConfig: Configuration = resolveWebpackConfig(config);
|
|
176
|
+
|
|
177
|
+
export default webpackConfig;
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
3. chrome扩展程序 配置示例
|
|
181
|
+
|
|
182
|
+
```TypeScript
|
|
183
|
+
import * as path from 'path';
|
|
184
|
+
import type {Configuration} from 'webpack';
|
|
185
|
+
import {resolveWebpackConfig, CodaUserConfig} from 'coda-builder';
|
|
186
|
+
|
|
187
|
+
const config: CodaUserConfig = {
|
|
188
|
+
platformTarget: 'chrome-ext',
|
|
189
|
+
techRoute: 'web',
|
|
190
|
+
entry: {
|
|
191
|
+
background: './src/background.ts',
|
|
192
|
+
sidepanel: './src/sidepanel.ts',
|
|
193
|
+
},
|
|
194
|
+
mode: 'production',
|
|
195
|
+
output: {
|
|
196
|
+
path: path.resolve(__dirname, 'dist'),
|
|
197
|
+
},
|
|
198
|
+
alias: {
|
|
199
|
+
'chat-shared-ui': path.resolve(__dirname, '../../coda-ui/resources'),
|
|
200
|
+
},
|
|
201
|
+
copyRules: [
|
|
202
|
+
{
|
|
203
|
+
type: 'single',
|
|
204
|
+
from: path.resolve(__dirname, 'manifest.json'),
|
|
205
|
+
to: 'manifest.json',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
type: 'template',
|
|
209
|
+
from: path.resolve(__dirname, '../../coda-ui/resources/chat.html'),
|
|
210
|
+
to: 'sidepanel.html',
|
|
211
|
+
data: {
|
|
212
|
+
'{{styleUri}}': 'main.css',
|
|
213
|
+
'{{scriptUri}}': 'sidepanel.js',
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
type: 'single',
|
|
218
|
+
from: path.resolve(__dirname, '../../coda-ui/resources/main.css'),
|
|
219
|
+
to: 'main.css',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const webpackConfig: Configuration = resolveWebpackConfig(config);
|
|
225
|
+
|
|
226
|
+
export default webpackConfig
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
4. vs code扩展程序 配置示例
|
|
230
|
+
|
|
231
|
+
```TypeScript
|
|
232
|
+
import * as path from 'path';
|
|
233
|
+
import type {Configuration} from 'webpack';
|
|
234
|
+
import {resolveWebpackConfig, CodaUserConfig} from 'coda-builder';
|
|
235
|
+
|
|
236
|
+
const config: CodaUserConfig = {
|
|
237
|
+
techRoute: 'typescript',
|
|
238
|
+
platformTarget: 'vscode-ext',
|
|
239
|
+
entry: './src/extension.ts',
|
|
240
|
+
mode: 'production',
|
|
241
|
+
output: {
|
|
242
|
+
path: path.resolve(__dirname, 'dist'),
|
|
243
|
+
filename: 'extension.js',
|
|
244
|
+
libraryTarget: 'commonjs',
|
|
245
|
+
},
|
|
246
|
+
alias: {
|
|
247
|
+
'chat-shared-ui': path.resolve(__dirname, '../../coda-ui/resources'),
|
|
248
|
+
},
|
|
249
|
+
copyRules: [
|
|
250
|
+
// 1. 复制共享的 chat.html
|
|
251
|
+
{
|
|
252
|
+
type: 'single',
|
|
253
|
+
from: path.resolve(__dirname, '../../coda-ui/resources/chat.html'),
|
|
254
|
+
to: 'main.html',
|
|
255
|
+
},
|
|
256
|
+
// 2. 复制共享的 main.css
|
|
257
|
+
{
|
|
258
|
+
type: 'single',
|
|
259
|
+
from: path.resolve(__dirname, '../../coda-ui/resources/main.css'),
|
|
260
|
+
to: 'main.css',
|
|
261
|
+
},
|
|
262
|
+
// 3. 复制 main.js
|
|
263
|
+
{
|
|
264
|
+
type: 'single',
|
|
265
|
+
from: path.resolve(__dirname, 'resources', 'main.js'),
|
|
266
|
+
to: 'main.js',
|
|
267
|
+
},
|
|
268
|
+
// 4. 复制 icon.svg
|
|
269
|
+
{
|
|
270
|
+
type: 'single',
|
|
271
|
+
from: path.resolve(__dirname, 'resources', 'icon.svg'),
|
|
272
|
+
to: 'icon.svg',
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const webpackConfig: Configuration = resolveWebpackConfig(config);
|
|
278
|
+
|
|
279
|
+
export default webpackConfig;
|
|
280
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coda-builder",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"build": "tsc",
|
|
6
|
+
"typecheck": "tsc --noEmit"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/src/index.js",
|
|
9
|
+
"types": "dist/src/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/src/index.d.ts",
|
|
13
|
+
"require": "./dist/src/index.js",
|
|
14
|
+
"import": "./dist/src/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"webpack": "^5.91.0",
|
|
19
|
+
"webpack-cli": "^5.1.4",
|
|
20
|
+
"webpack-dev-server": "^5.0.4",
|
|
21
|
+
"webpack-node-externals": "^3.0.0",
|
|
22
|
+
"webpackbar": "^7.0.0",
|
|
23
|
+
"webpack-bundle-analyzer": "^4.10.2",
|
|
24
|
+
"html-webpack-plugin": "^5.6.0",
|
|
25
|
+
"css-loader": "^7.1.2",
|
|
26
|
+
"css-minimizer-webpack-plugin": "^7.0.0",
|
|
27
|
+
"mini-css-extract-plugin": "^2.9.0",
|
|
28
|
+
"postcss": "^8.1.1",
|
|
29
|
+
"postcss-loader": "^8.1.1",
|
|
30
|
+
"postcss-preset-env": "^9.6.0",
|
|
31
|
+
"postcss-pxtorem": "^6.1.0",
|
|
32
|
+
"file-loader": "^6.2.0",
|
|
33
|
+
"url-loader": "^4.1.1",
|
|
34
|
+
"style-loader": "^4.0.0",
|
|
35
|
+
"compression-webpack-plugin": "^11.1.0",
|
|
36
|
+
"terser-webpack-plugin": "^5.6.1",
|
|
37
|
+
"speed-measure-webpack-v5-plugin": "^1.5.2",
|
|
38
|
+
"thread-loader": "4.0.2"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.0.0",
|
|
42
|
+
"@types/webpack": "^5.28.5",
|
|
43
|
+
"@types/webpack-dev-server": "^4.7.2",
|
|
44
|
+
"@types/webpackbar": "^5.0.0",
|
|
45
|
+
"@types/webpack-node-externals": "^3.0.4",
|
|
46
|
+
"@types/webpack-bundle-analyzer": "^4.7.0",
|
|
47
|
+
"ts-node": "^10.9.2",
|
|
48
|
+
"typescript": "^5.5.0"
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist"
|
|
52
|
+
]
|
|
53
|
+
}
|