UNPKG

@fchc8/vite-plugin-multi-page

Version:

A powerful Vite plugin for building multi-page applications with smart file routing and multi-strategy builds

492 lines (376 loc) 14 kB
# @fchc8/vite-plugin-multi-page > 中文文档 | [中文文档](./README.md) A powerful Vite plugin for multi-page application development, providing multi-strategy builds, TypeScript configuration support, and command-line tools. ## Features - 🎯 **Multi-page support**: Automatically discover page entry files - 🔧 **Multi-strategy builds**: Support configuring different builds for different pages - 📝 **TypeScript configuration**: Support TypeScript configuration files - 🚀 **CLI tool**: Provide command-line batch build tools - 🔄 **Hot reload**: Development server supports page hot reload - 📦 **Smart merge**: Automatically merge multi-strategy build results ## Install ```bash npm install @fchc8/vite-plugin-multi-page --save-dev ``` ## Quick Start ### 1. Configure Vite Add the plugin in `vite.config.ts`: ```typescript import { defineConfig } from 'vite'; import { viteMultiPage } from '@fchc8/vite-plugin-multi-page'; export default defineConfig({ plugins: [viteMultiPage()], }); ``` ### 2. Create Configuration File (Optional) The plugin provides reasonable default configurations, you can choose: **Option A: No Configuration File (Use Default Configuration)** - Automatically scan for page files under `src/pages/**/*.{ts,js}`, and the file with the name main as the page entry - Use `index.html` as the template - Create default build strategy **Option B: Simplest Configuration** Create `multipage.config.ts`: ```typescript import { defineConfig } from '@fchc8/vite-plugin-multi-page'; // Use all default values export default defineConfig(() => ({})); ``` **Option C: Complete Configuration** Create `multipage.config.ts` or `multipage.config.js`: ```typescript import { defineConfig } from 'vite-plugin-multi-page'; // Method 1: Object Configuration (Recommended) export default defineConfig({ entry: 'src/pages/**/*.{ts,js}', template: 'index.html', strategies: { // Strategy Configuration... }, }); // Method 2: Function Configuration (Dynamic Configuration) export default defineConfig(context => { const { mode, command, isCLI } = context; const isProduction = mode === 'production'; return { // Page entry matching rules entry: 'src/pages/**/*.{ts,js}', // HTML Template template: 'index.html', // Template Placeholder placeholder: '{{ENTRY_FILE}}', // Excluded Files exclude: ['src/shared/**/*.ts'], // Debug Mode debug: !isProduction || isCLI, // Build Strategy strategies: { default: { define: { IS_DEFAULT: true, API_BASE: isProduction ? '"https://api.example.com"' : '"http://localhost:3001/api"', }, build: { sourcemap: !isProduction, minify: isProduction ? 'esbuild' : false, }, }, mobile: { define: { IS_MOBILE: true, API_BASE: isProduction ? '"https://mobile-api.example.com"' : '"http://localhost:3001/mobile-api"', }, build: { target: ['es2015', 'chrome58', 'safari11'], minify: isProduction ? 'terser' : false, }, }, }, // Page Configuration Function pageConfigs: context => { // Determine the strategy based on the file path if (context.relativePath.includes('/mobile/')) { return { strategy: 'mobile', define: { PAGE_NAME: context.pageName, MOBILE_PAGE: true, }, }; } // Default Strategy return { strategy: 'default', define: { PAGE_NAME: context.pageName, DEFAULT_PAGE: true, }, }; }, }; }); ``` ### 3. Create Page Files Create page files according to the convention: **Note**: Even if you use the empty configuration `defineConfig({})`, the plugin will automatically use the default strategy to process all pages, ensuring maximum compatibility. ``` src/pages/ ├── home.js # → /home.html ├── about.js # → /about.html (Default Strategy) ├── mobile/ │ └── main.ts # → /mobile.html (Mobile Strategy) └── admin/ └── main.ts # → /admin.html (Admin Strategy) ``` ## Page Discovery Rules The plugin discovers page entries according to the following rules: 1. **First-level Files** (Priority 1): `src/pages/home.js` → `/home.html` 2. **Directory main files** (Priority 2): `src/pages/mobile/main.ts` → `/mobile.html` **Directory Priority Principle**: If both `src/pages/about.js` and `src/pages/about/main.ts` exist, `src/pages/about/main.ts` will be used. ## Build Strategy ### Strategy Configuration Strategy configuration supports all Vite configuration options: ```typescript strategies: { mobile: { define: { IS_MOBILE: true, }, build: { target: ['es2015'], minify: 'terser', terserOptions: { compress: { drop_console: true, }, }, }, // Other Vite configurations... }, } ``` ### Build Output Merge Strategy Control how build outputs are organized using the `merge` option: ```typescript export default defineConfig({ // ... other configurations merge: 'all' | 'page', }); ``` #### Available Modes - **`all`** (default): All HTML files in root directory, assets merged into `/dist/assets/` ``` dist/ ├── home.html ├── about.html ├── mobile.html └── assets/ ├── home-xxx.js ├── about-xxx.js └── shared-resource.svg ``` - **`page`**: Each page is independently packaged with its own complete set of resource copies ``` dist/ ├── home/ │ ├── index.html │ ├── assets/ │ │ ├── home-xxx.js │ │ └── button-loading.svg │ └── images/ ├── about/ │ ├── index.html │ ├── assets/ │ │ ├── about-xxx.js │ │ └── button-loading.svg │ └── images/ └── mobile/ ├── index.html ├── assets/ │ ├── mobile-xxx.js │ └── button-loading.svg └── images/ ``` #### Advantages of Page Mode - ✅ **Fully Independent**: Each page directory contains all required resources, can be deployed independently - ✅ **Avoid Conflicts**: Completely resolves shared resource attribution issues - ✅ **Clean Naming**: Resource files use clean file names without page prefixes - ✅ **Deployment Friendly**: Supports CDN distribution, micro-frontend architectures > **Note**: > > - Page mode creates resource copies for each page, which may increase overall build output size > - Suitable for scenarios requiring independent deployment or strict resource isolation > - Static assets from the `public/` directory are automatically copied to each page directory ### Page Strategy Assignment Assign strategies to pages through the `pageConfigs` function: ```typescript pageConfigs: context => { const { pageName, relativePath } = context; if (relativePath.includes('/mobile/')) { return { strategy: 'mobile' }; } if (pageName.startsWith('admin')) { return { strategy: 'admin' }; } return { strategy: 'default' }; }; ``` ## Command Line Tool ### Batch Build ```bash # Build all strategies npx vite-mp # Pass additional Vite parameters npx vite-mp --host --port 3000 # Enable debug mode npx vite-mp --debug ``` ### Development Server ```bash # Start development server (all pages) npm run dev # Only display pages with specific strategies npm run dev -- --strategy mobile ``` ## Usage Examples ### Page Mode for Independent Deployment Configure Page mode where each page gets complete independent resources: ```typescript // multipage.config.ts export default defineConfig({ entry: 'src/pages/**/*.{ts,js}', template: 'index.html', merge: 'page', // Enable Page mode strategies: { default: { build: { sourcemap: false, minify: 'esbuild', }, }, mobile: { build: { target: ['es2015'], minify: 'terser', }, }, }, pageConfigs: context => { if (context.relativePath.includes('/mobile/')) { return { strategy: 'mobile' }; } return { strategy: 'default' }; }, }); ``` Build result: Each page has independent resource files, avoiding shared resource missing issues. ### Shared Resource Handling In Page mode, shared resources (such as icons, style files) are copied to each page directory: ```typescript // src/pages/about/main.ts import buttonIcon from '../button-loading.svg'; // Shared resource // src/pages/mobile/main.ts import buttonIcon from '../button-loading.svg'; // Same shared resource ``` After building, both pages will have their own resource copies: - `dist/about/assets/button-loading-xxx.svg` - `dist/mobile/assets/button-loading-xxx.svg` ## Environment Variables - `VITE_BUILD_STRATEGY`: Specify a single strategy build - `VITE_MULTI_PAGE_BUILD_SINGLE_PAGE`: Specify single page build (used internally by Page mode) - `VITE_MULTI_PAGE_STRATEGY`: Current build strategy (automatically set) - `VITE_MULTI_PAGE_CURRENT_PAGE`: Current page name (automatically set in Page mode) - `VITE_MULTI_PAGE_MERGE_MODE`: Current merge mode (automatically set in Page mode) - `IS_MOBILE`: Mobile identifier (configured in define) - `API_BASE`: API base address (configured in define) ### Page Mode Environment Variable Injection In Page mode (`merge: 'page'`), you can inject specific environment variables for each page through the `pageEnvs` function: ```typescript // multipage.config.ts export default defineConfig({ merge: 'page', // Enable Page mode // Page environment variable injection function pageEnvs: context => { const { pageName, strategy, relativePath } = context; // Return page-specific environment variables const envs: Record<string, string> = { VITE_CURRENT_PAGE_NAME: pageName, VITE_CURRENT_STRATEGY: strategy || 'default', VITE_BUILD_TIMESTAMP: new Date().toISOString(), }; // Add specific variables based on page path if (relativePath.includes('/mobile/')) { envs.VITE_IS_MOBILE = 'true'; envs.VITE_API_URL = 'https://mobile-api.example.com'; } return envs; }, }); ``` #### Page Context The `pageEnvs` function receives a page context object containing the following information: - `pageName`: Page name (e.g., 'home', 'mobile') - `strategy`: Strategy name assigned to this page - `filePath`: Absolute path of the page entry file - `relativePath`: Relative path of the page entry file #### Use Cases 1. **Page-specific API configuration**: Set different API endpoints for different pages 2. **Page identification**: Identify the current page type at runtime 3. **Build information**: Inject build timestamps, version numbers, etc. 4. **Feature flags**: Enable or disable features for specific pages #### Usage in Code Injected environment variables can be accessed in code via `import.meta.env`: ```typescript // src/pages/mobile/main.ts console.log('Current page:', import.meta.env.VITE_CURRENT_PAGE_NAME); console.log('Current strategy:', import.meta.env.VITE_CURRENT_STRATEGY); console.log('Build time:', import.meta.env.VITE_BUILD_TIMESTAMP); if (import.meta.env.VITE_IS_MOBILE === 'true') { // Mobile-specific logic } ``` **Note**: The `pageEnvs` feature only works in Page mode (`merge: 'page'`) because only in this mode each page is built independently. ## TypeScript Support The plugin fully supports TypeScript configuration files: ```typescript // multipage.config.ts import type { ConfigFunction } from '@fchc8/vite-plugin-multi-page'; const config: ConfigFunction = context => { return { entry: 'src/pages/**/*.{ts,js}', // ... other configurations }; }; export default config; ``` ## API Reference ### Configuration Options | Option | Type | Default Value | Description | | ------------- | -------------------------- | -------------------------- | ------------------------------------------------------------- | | `entry` | `string` | `'src/pages/**/*.{ts,js}'` | Page entry matching rules | | `template` | `string` | `'index.html'` | HTML Template File | | `placeholder` | `string` | `'{{ENTRY_FILE}}'` | Template placeholder | | `exclude` | `string[]` | `[]` | Excluded file patterns | | `debug` | `boolean` | `false` | Enable debug logging | | `merge` | `'all' \| 'page'` | `'all'` | Build output merge strategy | | `strategies` | `Record<string, Strategy>` | `{}` | Build strategy configuration | | `pageConfigs` | `Function \| Object` | `{}` | Page configuration | | `pageEnvs` | `Function` | `() => null` | Page environment variable injection function (Page mode only) | ### Utility Functions ```typescript import { defineConfig, defineConfigTransform } from '@fchc8/vite-plugin-multi-page'; // Define configuration export default defineConfig(context => ({ // Configuration options })); // Configuration transformation const transform = defineConfigTransform((config, context) => { // Modify configuration return config; }); ``` ## Example Project See [example](./example) directory for the complete example project. ## License MIT License