@fchc8/vite-plugin-multi-page 1.6.0 → 1.7.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-EN.md CHANGED
@@ -2,18 +2,18 @@
2
2
 
3
3
  > 中文文档 | [中文文档](./README.md)
4
4
 
5
- A powerful Vite plugin for building multi-page applications with smart file routing and multi-strategy builds.
5
+ A powerful Vite plugin for multi-page application development, providing multi-strategy builds, TypeScript configuration support, and command-line tools.
6
6
 
7
7
  ## Features
8
8
 
9
9
  - 🎯 **Multi-page support**: Automatically discover page entry files
10
- - 🔧 **Multi-strategy builds**: Support configuring different build strategies for different pages
10
+ - 🔧 **Multi-strategy builds**: Support configuring different builds for different pages
11
11
  - 📝 **TypeScript configuration**: Support TypeScript configuration files
12
- - 🚀 **CLI tool**: Provide a command-line batch build tool
12
+ - 🚀 **CLI tool**: Provide command-line batch build tools
13
13
  - 🔄 **Hot reload**: Development server supports page hot reload
14
14
  - 📦 **Smart merge**: Automatically merge multi-strategy build results
15
15
 
16
- ## Installation
16
+ ## Install
17
17
 
18
18
  ```bash
19
19
  npm install @fchc8/vite-plugin-multi-page --save-dev
@@ -21,32 +21,78 @@ npm install @fchc8/vite-plugin-multi-page --save-dev
21
21
 
22
22
  ## Quick Start
23
23
 
24
- ### 1. Create a configuration file
24
+ ### 1. Configure Vite
25
25
 
26
- Create a `multipage.config.ts` or `multipage.config.js`:
26
+ Add the plugin in `vite.config.ts`:
27
+
28
+ ```typescript
29
+ import { defineConfig } from 'vite';
30
+ import { viteMultiPage } from '@fchc8/vite-plugin-multi-page';
31
+
32
+ export default defineConfig({
33
+ plugins: [viteMultiPage()],
34
+ });
35
+ ```
36
+
37
+ ### 2. Create Configuration File (Optional)
38
+
39
+ The plugin provides reasonable default configurations, you can choose:
40
+
41
+ **Option A: No Configuration File (Use Default Configuration)**
42
+
43
+ - Automatically scan for page files under `src/pages/**/*.{ts,js}`, and the file with the name main as the page entry
44
+ - Use `index.html` as the template
45
+ - Create default build strategy
46
+
47
+ **Option B: Simplest Configuration**
48
+
49
+ Create `multipage.config.ts`:
50
+
51
+ ```typescript
52
+ import { defineConfig } from '@fchc8/vite-plugin-multi-page';
53
+
54
+ // Use all default values
55
+ export default defineConfig(() => ({}));
56
+ ```
57
+
58
+ **Option C: Complete Configuration**
59
+
60
+ Create `multipage.config.ts` or `multipage.config.js`:
27
61
 
28
62
  ```typescript
29
- export default context => {
63
+ import { defineConfig } from 'vite-plugin-multi-page';
64
+
65
+ // Method 1: Object Configuration (Recommended)
66
+ export default defineConfig({
67
+ entry: 'src/pages/**/*.{ts,js}',
68
+ template: 'index.html',
69
+ strategies: {
70
+ // Strategy Configuration...
71
+ },
72
+ });
73
+
74
+ // Method 2: Function Configuration (Dynamic Configuration)
75
+ export default defineConfig(context => {
30
76
  const { mode, command, isCLI } = context;
31
77
  const isProduction = mode === 'production';
32
78
 
33
79
  return {
34
- // Page entry matching rule
80
+ // Page entry matching rules
35
81
  entry: 'src/pages/**/*.{ts,js}',
36
82
 
37
- // HTML template
83
+ // HTML Template
38
84
  template: 'index.html',
39
85
 
40
- // Template placeholder
86
+ // Template Placeholder
41
87
  placeholder: '{{ENTRY_FILE}}',
42
88
 
43
- // Excluded files
89
+ // Excluded Files
44
90
  exclude: ['src/shared/**/*.ts'],
45
91
 
46
- // Debug mode
92
+ // Debug Mode
47
93
  debug: !isProduction || isCLI,
48
94
 
49
- // Build strategy
95
+ // Build Strategy
50
96
  strategies: {
51
97
  default: {
52
98
  define: {
@@ -73,9 +119,9 @@ export default context => {
73
119
  },
74
120
  },
75
121
 
76
- // Page configuration function
122
+ // Page Configuration Function
77
123
  pageConfigs: context => {
78
- // Determine the application strategy based on the file path
124
+ // Determine the strategy based on the file path
79
125
  if (context.relativePath.includes('/mobile/')) {
80
126
  return {
81
127
  strategy: 'mobile',
@@ -86,7 +132,7 @@ export default context => {
86
132
  };
87
133
  }
88
134
 
89
- // Default strategy
135
+ // Default Strategy
90
136
  return {
91
137
  strategy: 'default',
92
138
  define: {
@@ -96,50 +142,39 @@ export default context => {
96
142
  };
97
143
  },
98
144
  };
99
- };
100
- ```
101
-
102
- ### 2. Configure Vite
103
-
104
- Add the plugin in `vite.config.ts`:
105
-
106
- ```typescript
107
- import { defineConfig } from 'vite';
108
- import { viteMultiPage } from '@fchc8/vite-plugin-multi-page';
109
-
110
- export default defineConfig({
111
- plugins: [viteMultiPage()],
112
145
  });
113
146
  ```
114
147
 
115
- ### 3. Create page files
148
+ ### 3. Create Page Files
116
149
 
117
150
  Create page files according to the convention:
118
151
 
152
+ **Note**: Even if you use the empty configuration `defineConfig({})`, the plugin will automatically use the default strategy to process all pages, ensuring maximum compatibility.
153
+
119
154
  ```
120
155
  src/pages/
121
156
  ├── home.js # → /home.html
122
- ├── about.js # → /about.html
157
+ ├── about.js # → /about.html (Default Strategy)
123
158
  ├── mobile/
124
- │ └── main.ts # → /mobile.html (mobile strategy)
159
+ │ └── main.ts # → /mobile.html (Mobile Strategy)
125
160
  └── admin/
126
- └── main.ts # → /admin.html
161
+ └── main.ts # → /admin.html (Admin Strategy)
127
162
  ```
128
163
 
129
- ## Page discovery rules
164
+ ## Page Discovery Rules
130
165
 
131
166
  The plugin discovers page entries according to the following rules:
132
167
 
133
- 1. **First-level files** (priority 1): `src/pages/home.js` → `/home.html`
134
- 2. **Directory main files** (priority 2): `src/pages/mobile/main.ts` → `/mobile.html`
168
+ 1. **First-level Files** (Priority 1): `src/pages/home.js` → `/home.html`
169
+ 2. **Directory main files** (Priority 2): `src/pages/mobile/main.ts` → `/mobile.html`
135
170
 
136
- **Directory priority rule**: If both `src/pages/about.js` and `src/pages/about/main.ts` exist, `src/pages/about/main.ts` will be used.
171
+ **Directory Priority Principle**: If both `src/pages/about.js` and `src/pages/about/main.ts` exist, `src/pages/about/main.ts` will be used.
137
172
 
138
- ## Build strategies
173
+ ## Build Strategy
139
174
 
140
- ### Strategy configuration
175
+ ### Strategy Configuration
141
176
 
142
- 策略配置支持所有 Vite 配置选项:
177
+ Strategy configuration supports all Vite configuration options:
143
178
 
144
179
  ```typescript
145
180
  strategies: {
@@ -161,7 +196,7 @@ strategies: {
161
196
  }
162
197
  ```
163
198
 
164
- ### Page strategy assignment
199
+ ### Page Strategy Assignment
165
200
 
166
201
  Assign strategies to pages through the `pageConfigs` function:
167
202
 
@@ -181,9 +216,9 @@ pageConfigs: context => {
181
216
  };
182
217
  ```
183
218
 
184
- ## 命令行工具
219
+ ## Command Line Tool
185
220
 
186
- ### 批量构建
221
+ ### Batch Build
187
222
 
188
223
  ```bash
189
224
  # Build all strategies
@@ -196,7 +231,7 @@ npx vite-mp --host --port 3000
196
231
  npx vite-mp --debug
197
232
  ```
198
233
 
199
- ### 开发服务器
234
+ ### Development Server
200
235
 
201
236
  ```bash
202
237
  # Start development server (all pages)
@@ -206,13 +241,13 @@ npm run dev
206
241
  npm run dev -- --strategy mobile
207
242
  ```
208
243
 
209
- ## Environment variables
244
+ ## Environment Variables
210
245
 
211
246
  - `VITE_BUILD_STRATEGY`: Specify a single strategy build
212
247
  - `IS_MOBILE`: Mobile identifier (configured in define)
213
248
  - `API_BASE`: API base address (configured in define)
214
249
 
215
- ## TypeScript support
250
+ ## TypeScript Support
216
251
 
217
252
  The plugin fully supports TypeScript configuration files:
218
253
 
@@ -230,21 +265,21 @@ const config: ConfigFunction = context => {
230
265
  export default config;
231
266
  ```
232
267
 
233
- ## API reference
268
+ ## API Reference
234
269
 
235
- ### Configuration options
270
+ ### Configuration Options
236
271
 
237
- | Option | Type | Default | Description |
238
- | ------------- | -------------------------- | -------------------------- | ---------------------------- |
239
- | `entry` | `string` | `'src/pages/**/*.{ts,js}'` | Page entry matching rule |
240
- | `template` | `string` | `'index.html'` | HTML template file |
241
- | `placeholder` | `string` | `'{{ENTRY_FILE}}'` | Template placeholder |
242
- | `exclude` | `string[]` | `[]` | Excluded file patterns |
243
- | `debug` | `boolean` | `false` | Enable debug log |
244
- | `strategies` | `Record<string, Strategy>` | `{}` | Build strategy configuration |
245
- | `pageConfigs` | `Function \| Object` | `{}` | Page |
272
+ | Option | Type | Default Value | Description |
273
+ | ------------- | -------------------------- | -------------------------- | ------------------------- |
274
+ | `entry` | `string` | `'src/pages/**/*.{ts,js}'` | Page entry matching rules |
275
+ | `template` | `string` | `'index.html'` | HTML Template File |
276
+ | `placeholder` | `string` | `'{{ENTRY_FILE}}'` | 模板占位符 |
277
+ | `exclude` | `string[]` | `[]` | 排除的文件模式 |
278
+ | `debug` | `boolean` | `false` | 启用调试日志 |
279
+ | `strategies` | `Record<string, Strategy>` | `{}` | 构建策略配置 |
280
+ | `pageConfigs` | `Function \| Object` | `{}` | 页面配置 |
246
281
 
247
- ### Utility functions
282
+ ### Utility Functions
248
283
 
249
284
  ```typescript
250
285
  import { defineConfig, defineConfigTransform } from '@fchc8/vite-plugin-multi-page';
@@ -261,9 +296,9 @@ const transform = defineConfigTransform((config, context) => {
261
296
  });
262
297
  ```
263
298
 
264
- ## Example project
299
+ ## Example Project
265
300
 
266
- See [example](./example) directory for a complete example project.
301
+ See [example](./example) directory for the complete example project.
267
302
 
268
303
  ## License
269
304
 
package/README.md CHANGED
@@ -40,7 +40,7 @@ export default defineConfig({
40
40
 
41
41
  **选项 A:无配置文件(使用默认配置)**
42
42
 
43
- - 自动扫描 `src/pages/**/*.{ts,js}` 下的页面文件
43
+ - 自动扫描 `src/pages/**/*.{ts,js}` 下的页面文件,目录下含有文件名main的文件作为页面入口
44
44
  - 使用 `index.html` 作为模板
45
45
  - 创建默认构建策略
46
46
 
package/dist/cli.js CHANGED
@@ -38,179 +38,27 @@ var init_cjs_shims = __esm({
38
38
  }
39
39
  });
40
40
 
41
- // src/config-loader.ts
42
- var config_loader_exports = {};
43
- __export(config_loader_exports, {
44
- hasCustomConfig: () => hasCustomConfig,
45
- loadUserConfig: () => loadUserConfig
46
- });
47
- function hasCustomConfig() {
48
- for (const filename of CONFIG_FILES) {
49
- const configPath = path.resolve(process.cwd(), filename);
50
- if (fs.existsSync(configPath)) {
51
- return true;
52
- }
53
- }
54
- return false;
55
- }
56
- async function loadUserConfig(context) {
57
- const customConfig = await loadCustomConfig();
58
- if (customConfig) {
59
- const result = customConfig(context);
60
- if (!result) {
61
- return {};
62
- }
63
- return result;
64
- }
65
- return null;
66
- }
67
- async function loadConfigFile(filePath) {
68
- if (filePath.endsWith(".ts")) {
69
- try {
70
- const code = await fs.promises.readFile(filePath, "utf-8");
71
- const esbuild = await import("esbuild");
72
- const result = await esbuild.transform(code, {
73
- loader: "ts",
74
- format: "cjs",
75
- // 使用 CommonJS 格式便于使用 Module._compile
76
- target: "node16",
77
- sourcemap: false
78
- });
79
- const tempModule = new import_node_module.Module(filePath);
80
- tempModule.filename = filePath;
81
- tempModule.paths = import_node_module.Module._nodeModulePaths(path.dirname(filePath));
82
- tempModule._compile(result.code, filePath);
83
- return tempModule.exports;
84
- } catch (esbuildError) {
85
- console.warn("esbuild \u8F6C\u8BD1\u5931\u8D25\uFF0C\u5C1D\u8BD5\u7B80\u5355\u8F6C\u6362:", esbuildError);
86
- const code = await fs.promises.readFile(filePath, "utf-8");
87
- const jsCode = code.replace(/export\s+default\s+/, "module.exports = ").replace(/import\s+.*?from\s+['"][^'"]*['"];?\s*/g, "").replace(/:\s*[^=,})\]]+/g, "");
88
- const tempModule = new import_node_module.Module(filePath);
89
- tempModule.filename = filePath;
90
- tempModule.paths = import_node_module.Module._nodeModulePaths(path.dirname(filePath));
91
- tempModule._compile(jsCode, filePath);
92
- return tempModule.exports;
93
- }
94
- }
95
- if (filePath.endsWith(".js") || filePath.endsWith(".mjs")) {
96
- const fileUrl = (0, import_node_url.pathToFileURL)(filePath).href;
97
- return import(`${fileUrl}?t=${Date.now()}`);
98
- }
99
- throw new Error(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u6587\u4EF6\u7C7B\u578B: ${filePath}`);
100
- }
101
- async function loadCustomConfig() {
102
- const cwd = process.cwd();
103
- for (const configFile of CONFIG_FILES) {
104
- const configPath = path.resolve(cwd, configFile);
105
- if (fs.existsSync(configPath)) {
106
- try {
107
- const configModule = await loadConfigFile(configPath);
108
- const configFunction = configModule.default || configModule;
109
- if (typeof configFunction === "function") {
110
- return configFunction;
111
- } else {
112
- console.warn(`\u914D\u7F6E\u6587\u4EF6 ${configFile} \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA\u4E00\u4E2A\u51FD\u6570`);
113
- }
114
- } catch (error) {
115
- if (configFile.endsWith(".ts")) {
116
- console.error(`\u52A0\u8F7DTypeScript\u914D\u7F6E\u6587\u4EF6 ${configFile} \u5931\u8D25:`, error);
117
- console.log("\u63D0\u793A\uFF1A\u786E\u4FDD\u4F60\u7684\u9879\u76EE\u652F\u6301TypeScript\uFF0C\u6216\u8005\u4F7F\u7528 .js/.mjs \u914D\u7F6E\u6587\u4EF6");
118
- } else {
119
- console.error(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6 ${configFile} \u5931\u8D25:`, error);
120
- }
121
- }
122
- }
123
- }
124
- return null;
125
- }
126
- var fs, path, import_node_url, import_node_module, CONFIG_FILES;
127
- var init_config_loader = __esm({
128
- "src/config-loader.ts"() {
129
- "use strict";
130
- init_cjs_shims();
131
- fs = __toESM(require("fs"));
132
- path = __toESM(require("path"));
133
- import_node_url = require("url");
134
- import_node_module = require("module");
135
- CONFIG_FILES = [
136
- "multipage.config.js",
137
- "multipage.config.mjs",
138
- "multipage.config.ts"
139
- ];
140
- }
141
- });
142
-
143
- // src/defaults.ts
144
- var defaults_exports = {};
145
- __export(defaults_exports, {
146
- DEFAULT_CONFIG: () => DEFAULT_CONFIG,
147
- isEmptyConfig: () => isEmptyConfig,
148
- mergeWithDefaults: () => mergeWithDefaults
149
- });
150
- function mergeWithDefaults(userConfig) {
151
- if (!userConfig) {
152
- return { ...DEFAULT_CONFIG };
153
- }
154
- return {
155
- entry: userConfig.entry ?? DEFAULT_CONFIG.entry,
156
- exclude: userConfig.exclude ?? DEFAULT_CONFIG.exclude,
157
- template: userConfig.template ?? DEFAULT_CONFIG.template,
158
- placeholder: userConfig.placeholder ?? DEFAULT_CONFIG.placeholder,
159
- debug: userConfig.debug ?? DEFAULT_CONFIG.debug,
160
- strategies: userConfig.strategies ?? DEFAULT_CONFIG.strategies,
161
- pageConfigs: userConfig.pageConfigs ?? DEFAULT_CONFIG.pageConfigs,
162
- __forceBuildStrategy: userConfig.__forceBuildStrategy
163
- };
164
- }
165
- function isEmptyConfig(config) {
166
- if (Object.keys(config).length === 0) {
167
- return true;
168
- }
169
- const hasValidEntry = config.entry && config.entry !== DEFAULT_CONFIG.entry;
170
- const hasValidStrategies = config.strategies && Object.keys(config.strategies).length > 0;
171
- const hasValidPageConfigs = config.pageConfigs && (typeof config.pageConfigs === "function" || Object.keys(config.pageConfigs).length > 0);
172
- return !hasValidEntry && !hasValidStrategies && !hasValidPageConfigs;
173
- }
174
- var DEFAULT_CONFIG;
175
- var init_defaults = __esm({
176
- "src/defaults.ts"() {
177
- "use strict";
178
- init_cjs_shims();
179
- DEFAULT_CONFIG = {
180
- entry: "src/pages/**/*.{ts,js}",
181
- exclude: [],
182
- template: "index.html",
183
- placeholder: "{{ENTRY_FILE}}",
184
- debug: false,
185
- strategies: {
186
- default: {}
187
- },
188
- pageConfigs: {}
189
- };
190
- }
191
- });
192
-
193
41
  // src/file-filter.ts
194
42
  function filterEntryFiles(files, entry, exclude, _log) {
195
43
  const result = [];
196
44
  const nameToFile = /* @__PURE__ */ new Map();
197
45
  let basePattern = entry.replace(/\/\*.*$/, "");
198
46
  if (!basePattern || basePattern === entry) {
199
- basePattern = path2.dirname(entry.split("*")[0]);
47
+ basePattern = path.dirname(entry.split("*")[0]);
200
48
  }
201
49
  const candidateFiles = [];
202
50
  for (const file of files) {
203
51
  if (exclude.includes(file)) {
204
52
  continue;
205
53
  }
206
- const relativePath = path2.relative(basePattern, file);
207
- const pathParts = relativePath.split(path2.sep);
54
+ const relativePath = path.relative(basePattern, file);
55
+ const pathParts = relativePath.split(path.sep);
208
56
  if (pathParts.length === 1) {
209
57
  const fileName = pathParts[0];
210
- const name = path2.basename(fileName, path2.extname(fileName));
58
+ const name = path.basename(fileName, path.extname(fileName));
211
59
  candidateFiles.push({ name, file, priority: 1 });
212
60
  } else if (pathParts.length >= 2) {
213
- const fileName = path2.basename(file, path2.extname(file));
61
+ const fileName = path.basename(file, path.extname(file));
214
62
  const dirName = pathParts[0];
215
63
  if (fileName === "main") {
216
64
  candidateFiles.push({ name: dirName, file, priority: 2 });
@@ -232,12 +80,12 @@ function filterEntryFiles(files, entry, exclude, _log) {
232
80
  }
233
81
  return result;
234
82
  }
235
- var path2;
83
+ var path;
236
84
  var init_file_filter = __esm({
237
85
  "src/file-filter.ts"() {
238
86
  "use strict";
239
87
  init_cjs_shims();
240
- path2 = __toESM(require("path"));
88
+ path = __toESM(require("path"));
241
89
  }
242
90
  });
243
91
 
@@ -334,7 +182,7 @@ function generateBuildConfig(options) {
334
182
  const pageContext = {
335
183
  pageName: entryFile.name,
336
184
  filePath: entryFile.file,
337
- relativePath: path3.relative(process.cwd(), entryFile.file)
185
+ relativePath: path2.relative(process.cwd(), entryFile.file)
338
186
  };
339
187
  const pageConfig = getPageConfig(pageConfigs, pageContext, log);
340
188
  const strategyName = (pageConfig == null ? void 0 : pageConfig.strategy) || "default";
@@ -415,7 +263,7 @@ function generateStrategyConfig(strategyName, pages, entryFiles, strategyConfig,
415
263
  const pageContext = {
416
264
  pageName,
417
265
  filePath: entryFile.file,
418
- relativePath: path3.relative(process.cwd(), entryFile.file),
266
+ relativePath: path2.relative(process.cwd(), entryFile.file),
419
267
  strategy: strategyName
420
268
  };
421
269
  const pageConfig = getPageConfig(pageConfigs, pageContext, log);
@@ -424,17 +272,17 @@ function generateStrategyConfig(strategyName, pages, entryFiles, strategyConfig,
424
272
  }
425
273
  let templatePath = defaultTemplate;
426
274
  const pageSpecificTemplate = `${pageName}.html`;
427
- if (fs2.existsSync(path3.resolve(process.cwd(), pageSpecificTemplate))) {
275
+ if (fs.existsSync(path2.resolve(process.cwd(), pageSpecificTemplate))) {
428
276
  templatePath = pageSpecificTemplate;
429
277
  } else if (pageConfig == null ? void 0 : pageConfig.template) {
430
278
  templatePath = pageConfig.template;
431
279
  }
432
- const templateFullPath = path3.resolve(process.cwd(), templatePath);
433
- if (!fs2.existsSync(templateFullPath)) {
280
+ const templateFullPath = path2.resolve(process.cwd(), templatePath);
281
+ if (!fs.existsSync(templateFullPath)) {
434
282
  log(`\u8B66\u544A: \u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${templatePath}`);
435
283
  continue;
436
284
  }
437
- let templateContent = fs2.readFileSync(templateFullPath, "utf-8");
285
+ let templateContent = fs.readFileSync(templateFullPath, "utf-8");
438
286
  if (templateContent.includes(placeholder)) {
439
287
  const entryPath = `./${entryFile.file}`;
440
288
  templateContent = templateContent.replace(
@@ -442,8 +290,8 @@ function generateStrategyConfig(strategyName, pages, entryFiles, strategyConfig,
442
290
  entryPath
443
291
  );
444
292
  }
445
- const tempHtmlPath = path3.resolve(process.cwd(), `.temp.mp.${pageName}.html`);
446
- fs2.writeFileSync(tempHtmlPath, templateContent);
293
+ const tempHtmlPath = path2.resolve(process.cwd(), `.temp.mp.${pageName}.html`);
294
+ fs.writeFileSync(tempHtmlPath, templateContent);
447
295
  tempFiles.push(tempHtmlPath);
448
296
  htmlInputs[pageName] = tempHtmlPath;
449
297
  }
@@ -486,22 +334,22 @@ function getViteOutputDirectory(viteBuildArgs = []) {
486
334
  const outDirIndex = viteBuildArgs.findIndex((arg) => arg === "--outDir");
487
335
  if (outDirIndex !== -1 && outDirIndex + 1 < viteBuildArgs.length) {
488
336
  const outDir = viteBuildArgs[outDirIndex + 1];
489
- return path3.resolve(process.cwd(), outDir);
337
+ return path2.resolve(process.cwd(), outDir);
490
338
  }
491
339
  const outDirArg = viteBuildArgs.find((arg) => arg.startsWith("--outDir="));
492
340
  if (outDirArg) {
493
341
  const outDir = outDirArg.split("=")[1];
494
- return path3.resolve(process.cwd(), outDir);
342
+ return path2.resolve(process.cwd(), outDir);
495
343
  }
496
- return path3.resolve(process.cwd(), "dist");
344
+ return path2.resolve(process.cwd(), "dist");
497
345
  }
498
346
  function cleanViteOutputDirectory(viteBuildArgs = []) {
499
347
  const outputDir = getViteOutputDirectory(viteBuildArgs);
500
348
  const log = createLogger(true);
501
349
  try {
502
- if (fs2.existsSync(outputDir)) {
503
- fs2.rmSync(outputDir, { recursive: true, force: true });
504
- log(`\u{1F9F9} \u6E05\u7406\u8F93\u51FA\u76EE\u5F55: ${path3.relative(process.cwd(), outputDir)}`);
350
+ if (fs.existsSync(outputDir)) {
351
+ fs.rmSync(outputDir, { recursive: true, force: true });
352
+ log(`\u{1F9F9} \u6E05\u7406\u8F93\u51FA\u76EE\u5F55: ${path2.relative(process.cwd(), outputDir)}`);
505
353
  }
506
354
  } catch (error) {
507
355
  log(`\u26A0\uFE0F \u6E05\u7406\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${outputDir}`, error);
@@ -521,7 +369,7 @@ function getAvailableStrategies(options) {
521
369
  const pageContext = {
522
370
  pageName: entryFile.name,
523
371
  filePath: entryFile.file,
524
- relativePath: path3.relative(process.cwd(), entryFile.file)
372
+ relativePath: path2.relative(process.cwd(), entryFile.file)
525
373
  };
526
374
  const pageConfig = getPageConfig(pageConfigs, pageContext, log);
527
375
  const strategyName = (pageConfig == null ? void 0 : pageConfig.strategy) || "default";
@@ -533,21 +381,173 @@ function getAvailableStrategies(options) {
533
381
  return ["default"];
534
382
  }
535
383
  }
536
- var import_vite, import_glob, path3, fs2;
384
+ var import_vite, import_glob, path2, fs;
537
385
  var init_build_config = __esm({
538
386
  "src/build-config.ts"() {
539
387
  "use strict";
540
388
  init_cjs_shims();
541
389
  import_vite = require("vite");
542
390
  import_glob = require("glob");
543
- path3 = __toESM(require("path"));
544
- fs2 = __toESM(require("fs"));
391
+ path2 = __toESM(require("path"));
392
+ fs = __toESM(require("fs"));
545
393
  init_file_filter();
546
394
  init_page_config();
547
395
  init_utils();
548
396
  }
549
397
  });
550
398
 
399
+ // src/config-loader.ts
400
+ var config_loader_exports = {};
401
+ __export(config_loader_exports, {
402
+ hasCustomConfig: () => hasCustomConfig,
403
+ loadUserConfig: () => loadUserConfig
404
+ });
405
+ function hasCustomConfig() {
406
+ for (const filename of CONFIG_FILES) {
407
+ const configPath = path3.resolve(process.cwd(), filename);
408
+ if (fs2.existsSync(configPath)) {
409
+ return true;
410
+ }
411
+ }
412
+ return false;
413
+ }
414
+ async function loadUserConfig(context) {
415
+ const customConfig = await loadCustomConfig();
416
+ if (customConfig) {
417
+ const result = customConfig(context);
418
+ if (!result) {
419
+ return {};
420
+ }
421
+ return result;
422
+ }
423
+ return null;
424
+ }
425
+ async function loadConfigFile(filePath) {
426
+ if (filePath.endsWith(".ts")) {
427
+ try {
428
+ const code = await fs2.promises.readFile(filePath, "utf-8");
429
+ const esbuild = await import("esbuild");
430
+ const result = await esbuild.transform(code, {
431
+ loader: "ts",
432
+ format: "cjs",
433
+ // 使用 CommonJS 格式便于使用 Module._compile
434
+ target: "node16",
435
+ sourcemap: false
436
+ });
437
+ const tempModule = new import_node_module.Module(filePath);
438
+ tempModule.filename = filePath;
439
+ tempModule.paths = import_node_module.Module._nodeModulePaths(path3.dirname(filePath));
440
+ tempModule._compile(result.code, filePath);
441
+ return tempModule.exports;
442
+ } catch (esbuildError) {
443
+ console.warn("esbuild \u8F6C\u8BD1\u5931\u8D25\uFF0C\u5C1D\u8BD5\u7B80\u5355\u8F6C\u6362:", esbuildError);
444
+ const code = await fs2.promises.readFile(filePath, "utf-8");
445
+ const jsCode = code.replace(/export\s+default\s+/, "module.exports = ").replace(/import\s+.*?from\s+['"][^'"]*['"];?\s*/g, "").replace(/:\s*[^=,})\]]+/g, "");
446
+ const tempModule = new import_node_module.Module(filePath);
447
+ tempModule.filename = filePath;
448
+ tempModule.paths = import_node_module.Module._nodeModulePaths(path3.dirname(filePath));
449
+ tempModule._compile(jsCode, filePath);
450
+ return tempModule.exports;
451
+ }
452
+ }
453
+ if (filePath.endsWith(".js") || filePath.endsWith(".mjs")) {
454
+ const fileUrl = (0, import_node_url.pathToFileURL)(filePath).href;
455
+ return import(`${fileUrl}?t=${Date.now()}`);
456
+ }
457
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u6587\u4EF6\u7C7B\u578B: ${filePath}`);
458
+ }
459
+ async function loadCustomConfig() {
460
+ const cwd = process.cwd();
461
+ for (const configFile of CONFIG_FILES) {
462
+ const configPath = path3.resolve(cwd, configFile);
463
+ if (fs2.existsSync(configPath)) {
464
+ try {
465
+ const configModule = await loadConfigFile(configPath);
466
+ const configFunction = configModule.default || configModule;
467
+ if (typeof configFunction === "function") {
468
+ return configFunction;
469
+ } else {
470
+ console.warn(`\u914D\u7F6E\u6587\u4EF6 ${configFile} \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA\u4E00\u4E2A\u51FD\u6570`);
471
+ }
472
+ } catch (error) {
473
+ if (configFile.endsWith(".ts")) {
474
+ console.error(`\u52A0\u8F7DTypeScript\u914D\u7F6E\u6587\u4EF6 ${configFile} \u5931\u8D25:`, error);
475
+ console.log("\u63D0\u793A\uFF1A\u786E\u4FDD\u4F60\u7684\u9879\u76EE\u652F\u6301TypeScript\uFF0C\u6216\u8005\u4F7F\u7528 .js/.mjs \u914D\u7F6E\u6587\u4EF6");
476
+ } else {
477
+ console.error(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6 ${configFile} \u5931\u8D25:`, error);
478
+ }
479
+ }
480
+ }
481
+ }
482
+ return null;
483
+ }
484
+ var fs2, path3, import_node_url, import_node_module, CONFIG_FILES;
485
+ var init_config_loader = __esm({
486
+ "src/config-loader.ts"() {
487
+ "use strict";
488
+ init_cjs_shims();
489
+ fs2 = __toESM(require("fs"));
490
+ path3 = __toESM(require("path"));
491
+ import_node_url = require("url");
492
+ import_node_module = require("module");
493
+ CONFIG_FILES = [
494
+ "multipage.config.js",
495
+ "multipage.config.mjs",
496
+ "multipage.config.ts"
497
+ ];
498
+ }
499
+ });
500
+
501
+ // src/defaults.ts
502
+ var defaults_exports = {};
503
+ __export(defaults_exports, {
504
+ DEFAULT_CONFIG: () => DEFAULT_CONFIG,
505
+ isEmptyConfig: () => isEmptyConfig,
506
+ mergeWithDefaults: () => mergeWithDefaults
507
+ });
508
+ function mergeWithDefaults(userConfig) {
509
+ if (!userConfig) {
510
+ return { ...DEFAULT_CONFIG };
511
+ }
512
+ return {
513
+ entry: userConfig.entry ?? DEFAULT_CONFIG.entry,
514
+ exclude: userConfig.exclude ?? DEFAULT_CONFIG.exclude,
515
+ template: userConfig.template ?? DEFAULT_CONFIG.template,
516
+ placeholder: userConfig.placeholder ?? DEFAULT_CONFIG.placeholder,
517
+ debug: userConfig.debug ?? DEFAULT_CONFIG.debug,
518
+ strategies: userConfig.strategies ?? DEFAULT_CONFIG.strategies,
519
+ pageConfigs: userConfig.pageConfigs ?? DEFAULT_CONFIG.pageConfigs,
520
+ __forceBuildStrategy: userConfig.__forceBuildStrategy
521
+ };
522
+ }
523
+ function isEmptyConfig(config) {
524
+ if (Object.keys(config).length === 0) {
525
+ return true;
526
+ }
527
+ const hasValidEntry = config.entry && config.entry !== DEFAULT_CONFIG.entry;
528
+ const hasValidStrategies = config.strategies && Object.keys(config.strategies).length > 0;
529
+ const hasValidPageConfigs = config.pageConfigs && (typeof config.pageConfigs === "function" || Object.keys(config.pageConfigs).length > 0);
530
+ return !hasValidEntry && !hasValidStrategies && !hasValidPageConfigs;
531
+ }
532
+ var DEFAULT_CONFIG;
533
+ var init_defaults = __esm({
534
+ "src/defaults.ts"() {
535
+ "use strict";
536
+ init_cjs_shims();
537
+ DEFAULT_CONFIG = {
538
+ entry: "src/pages/**/*.{ts,js}",
539
+ exclude: [],
540
+ template: "index.html",
541
+ placeholder: "{{ENTRY_FILE}}",
542
+ debug: false,
543
+ strategies: {
544
+ default: {}
545
+ },
546
+ pageConfigs: {}
547
+ };
548
+ }
549
+ });
550
+
551
551
  // src/cli.ts
552
552
  var cli_exports = {};
553
553
  __export(cli_exports, {
@@ -559,6 +559,7 @@ var import_node_child_process = require("child_process");
559
559
  var fs3 = __toESM(require("fs"));
560
560
  var path4 = __toESM(require("path"));
561
561
  var glob2 = __toESM(require("glob"));
562
+ init_build_config();
562
563
  function parseArgs() {
563
564
  const args = process.argv.slice(2);
564
565
  const viteBuildArgs = [];
@@ -635,19 +636,18 @@ function buildStrategy(strategy, viteBuildArgs, debug) {
635
636
  }
636
637
  child.on("close", (code) => {
637
638
  const success = code === 0;
638
- const outputDir = `dist/${strategy}`;
639
+ const actualOutputDir = getViteOutputDirectory(viteBuildArgs);
639
640
  if (success) {
640
641
  log(`\u2705 \u7B56\u7565 ${strategy} \u6784\u5EFA\u6210\u529F`);
641
642
  try {
642
- const outputPath = path4.resolve(process.cwd(), outputDir);
643
- if (fs3.existsSync(outputPath)) {
644
- const files = fs3.readdirSync(outputPath);
643
+ if (fs3.existsSync(actualOutputDir)) {
644
+ const files = fs3.readdirSync(actualOutputDir);
645
645
  for (const file of files) {
646
646
  if (file.startsWith(".temp.mp.") && file.endsWith(".html")) {
647
- const oldPath = path4.resolve(outputPath, file);
647
+ const oldPath = path4.resolve(actualOutputDir, file);
648
648
  const name = file.replace(/^\.temp\.mp\./, "").replace(/\.html$/, "");
649
649
  const newName = `${name}.html`;
650
- const newPath = path4.resolve(outputPath, newName);
650
+ const newPath = path4.resolve(actualOutputDir, newName);
651
651
  fs3.renameSync(oldPath, newPath);
652
652
  log(`\u91CD\u547D\u540DHTML: ${file} -> ${newName}`);
653
653
  }
@@ -666,16 +666,17 @@ function buildStrategy(strategy, viteBuildArgs, debug) {
666
666
  strategy,
667
667
  success,
668
668
  error: success ? void 0 : errorOutput || `\u6784\u5EFA\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${code}`,
669
- outputDir
669
+ outputDir: actualOutputDir
670
670
  });
671
671
  });
672
672
  child.on("error", (error) => {
673
673
  log(`\u274C \u7B56\u7565 ${strategy} \u6784\u5EFA\u51FA\u9519:`, error.message);
674
+ const actualOutputDir = getViteOutputDirectory(viteBuildArgs);
674
675
  resolve4({
675
676
  strategy,
676
677
  success: false,
677
678
  error: error.message,
678
- outputDir: `dist/${strategy}`
679
+ outputDir: actualOutputDir
679
680
  });
680
681
  });
681
682
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fchc8/vite-plugin-multi-page",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "A powerful Vite plugin for building multi-page applications with smart file routing and multi-strategy builds",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",