svger-cli 2.0.8 → 3.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/CHANGELOG.md +159 -0
- package/README.md +348 -15
- package/dist/index.d.ts +30 -0
- package/dist/index.js +33 -0
- package/dist/integrations/babel.d.ts +58 -0
- package/dist/integrations/babel.js +221 -0
- package/dist/integrations/jest-preset.d.ts +44 -0
- package/dist/integrations/jest-preset.js +169 -0
- package/dist/integrations/nextjs.d.ts +56 -0
- package/dist/integrations/nextjs.js +140 -0
- package/dist/integrations/rollup.d.ts +29 -0
- package/dist/integrations/rollup.js +197 -0
- package/dist/integrations/vite.d.ts +29 -0
- package/dist/integrations/vite.js +221 -0
- package/dist/integrations/webpack.d.ts +84 -0
- package/dist/integrations/webpack.js +273 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +2 -1
- package/dist/types/integrations.d.ts +255 -0
- package/dist/types/integrations.js +4 -0
- package/docs/INTEGRATION-IMPLEMENTATION-SUMMARY.md +448 -0
- package/docs/INTEGRATIONS.md +543 -0
- package/examples/babel.config.example.js +182 -0
- package/examples/jest.config.example.js +158 -0
- package/examples/next.config.example.js +133 -0
- package/examples/rollup.config.example.js +129 -0
- package/examples/vite.config.example.js +98 -0
- package/examples/webpack.config.example.js +88 -0
- package/package.json +74 -3
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Next.js Plugin for SVGER-CLI
|
|
3
|
+
*
|
|
4
|
+
* Automatically converts SVG files to framework components in Next.js applications
|
|
5
|
+
* with full SSR support, HMR, and webpack integration.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```js
|
|
9
|
+
* // next.config.js
|
|
10
|
+
* const { withSvger } = require('svger-cli/nextjs');
|
|
11
|
+
*
|
|
12
|
+
* module.exports = withSvger({
|
|
13
|
+
* svger: {
|
|
14
|
+
* source: './src/icons',
|
|
15
|
+
* output: './src/components/icons',
|
|
16
|
+
* framework: 'react',
|
|
17
|
+
* typescript: true
|
|
18
|
+
* },
|
|
19
|
+
* // ... other Next.js config
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { SvgerWebpackPlugin } from './webpack.js';
|
|
24
|
+
import { logger } from '../core/logger.js';
|
|
25
|
+
/**
|
|
26
|
+
* Next.js plugin configuration wrapper
|
|
27
|
+
*/
|
|
28
|
+
export function withSvger(nextConfig = {}) {
|
|
29
|
+
return {
|
|
30
|
+
...nextConfig,
|
|
31
|
+
webpack(config, options) {
|
|
32
|
+
const { isServer } = options;
|
|
33
|
+
// Get svger options from Next.js config
|
|
34
|
+
const svgerOptions = nextConfig.svger || {};
|
|
35
|
+
// Add SVGER webpack plugin
|
|
36
|
+
if (!config.plugins) {
|
|
37
|
+
config.plugins = [];
|
|
38
|
+
}
|
|
39
|
+
// Only run on client build or if explicitly enabled for SSR
|
|
40
|
+
if (!isServer || svgerOptions.ssr !== false) {
|
|
41
|
+
const pluginInstance = new SvgerWebpackPlugin({
|
|
42
|
+
source: svgerOptions.source,
|
|
43
|
+
output: svgerOptions.output,
|
|
44
|
+
framework: svgerOptions.framework || 'react',
|
|
45
|
+
typescript: svgerOptions.typescript,
|
|
46
|
+
config: svgerOptions.config,
|
|
47
|
+
include: svgerOptions.include,
|
|
48
|
+
exclude: svgerOptions.exclude,
|
|
49
|
+
hmr: svgerOptions.hmr,
|
|
50
|
+
generateIndex: svgerOptions.generateIndex,
|
|
51
|
+
});
|
|
52
|
+
config.plugins.push(pluginInstance);
|
|
53
|
+
if (!isServer) {
|
|
54
|
+
logger.info('SVGER Next.js Plugin: Configured for client build');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
logger.info('SVGER Next.js Plugin: Configured for server build');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Add SVG file handling rule
|
|
61
|
+
config.module.rules.push({
|
|
62
|
+
test: /\.svg$/,
|
|
63
|
+
issuer: /\.[jt]sx?$/,
|
|
64
|
+
use: [
|
|
65
|
+
{
|
|
66
|
+
loader: 'svger-cli/webpack-loader',
|
|
67
|
+
options: {
|
|
68
|
+
framework: svgerOptions.framework || 'react',
|
|
69
|
+
typescript: svgerOptions.typescript,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
// Call user's custom webpack config if provided
|
|
75
|
+
if (svgerOptions.webpack && typeof svgerOptions.webpack === 'function') {
|
|
76
|
+
return svgerOptions.webpack(config, options);
|
|
77
|
+
}
|
|
78
|
+
// Call original webpack config if provided
|
|
79
|
+
if (typeof nextConfig.webpack === 'function') {
|
|
80
|
+
return nextConfig.webpack(config, options);
|
|
81
|
+
}
|
|
82
|
+
return config;
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Standalone Next.js webpack plugin
|
|
88
|
+
* Can be used directly in next.config.js webpack function
|
|
89
|
+
*/
|
|
90
|
+
export class SvgerNextJsPlugin extends SvgerWebpackPlugin {
|
|
91
|
+
constructor(options = {}) {
|
|
92
|
+
super({
|
|
93
|
+
source: options.source,
|
|
94
|
+
output: options.output,
|
|
95
|
+
framework: options.framework || 'react',
|
|
96
|
+
typescript: options.typescript,
|
|
97
|
+
config: options.config,
|
|
98
|
+
include: options.include,
|
|
99
|
+
exclude: options.exclude,
|
|
100
|
+
hmr: options.hmr,
|
|
101
|
+
generateIndex: options.generateIndex,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Helper function to configure SVG imports in Next.js
|
|
107
|
+
* For use in next.config.js
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```js
|
|
111
|
+
* const { configureSvgImports } = require('svger-cli/nextjs');
|
|
112
|
+
*
|
|
113
|
+
* module.exports = {
|
|
114
|
+
* webpack(config, options) {
|
|
115
|
+
* configureSvgImports(config, {
|
|
116
|
+
* framework: 'react',
|
|
117
|
+
* typescript: true
|
|
118
|
+
* });
|
|
119
|
+
* return config;
|
|
120
|
+
* }
|
|
121
|
+
* };
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export function configureSvgImports(webpackConfig, options = {}) {
|
|
125
|
+
webpackConfig.module.rules.push({
|
|
126
|
+
test: /\.svg$/,
|
|
127
|
+
issuer: /\.[jt]sx?$/,
|
|
128
|
+
use: [
|
|
129
|
+
{
|
|
130
|
+
loader: 'svger-cli/webpack-loader',
|
|
131
|
+
options: {
|
|
132
|
+
framework: options.framework || 'react',
|
|
133
|
+
typescript: options.typescript !== undefined ? options.typescript : true,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Default export
|
|
140
|
+
export default withSvger;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Rollup Plugin for SVGER-CLI
|
|
3
|
+
*
|
|
4
|
+
* Automatically converts SVG files to framework components during Rollup builds
|
|
5
|
+
* with full bundle optimization and tree-shaking support.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```js
|
|
9
|
+
* // rollup.config.js
|
|
10
|
+
* import { svgerRollupPlugin } from 'svger-cli/rollup';
|
|
11
|
+
*
|
|
12
|
+
* export default {
|
|
13
|
+
* plugins: [
|
|
14
|
+
* svgerRollupPlugin({
|
|
15
|
+
* source: './src/icons',
|
|
16
|
+
* output: './src/components/icons',
|
|
17
|
+
* framework: 'react',
|
|
18
|
+
* typescript: true
|
|
19
|
+
* })
|
|
20
|
+
* ]
|
|
21
|
+
* };
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import type { RollupPluginOptions } from '../types/integrations.js';
|
|
25
|
+
/**
|
|
26
|
+
* Rollup Plugin for SVGER-CLI
|
|
27
|
+
*/
|
|
28
|
+
export declare function svgerRollupPlugin(options?: RollupPluginOptions): any;
|
|
29
|
+
export default svgerRollupPlugin;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Rollup Plugin for SVGER-CLI
|
|
3
|
+
*
|
|
4
|
+
* Automatically converts SVG files to framework components during Rollup builds
|
|
5
|
+
* with full bundle optimization and tree-shaking support.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```js
|
|
9
|
+
* // rollup.config.js
|
|
10
|
+
* import { svgerRollupPlugin } from 'svger-cli/rollup';
|
|
11
|
+
*
|
|
12
|
+
* export default {
|
|
13
|
+
* plugins: [
|
|
14
|
+
* svgerRollupPlugin({
|
|
15
|
+
* source: './src/icons',
|
|
16
|
+
* output: './src/components/icons',
|
|
17
|
+
* framework: 'react',
|
|
18
|
+
* typescript: true
|
|
19
|
+
* })
|
|
20
|
+
* ]
|
|
21
|
+
* };
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import path from 'path';
|
|
25
|
+
import { FileSystem } from '../utils/native.js';
|
|
26
|
+
import { svgProcessor } from '../processors/svg-processor.js';
|
|
27
|
+
import { configService } from '../services/config.js';
|
|
28
|
+
import { logger } from '../core/logger.js';
|
|
29
|
+
const PLUGIN_NAME = 'svger-rollup-plugin';
|
|
30
|
+
/**
|
|
31
|
+
* Rollup Plugin for SVGER-CLI
|
|
32
|
+
*/
|
|
33
|
+
export function svgerRollupPlugin(options = {}) {
|
|
34
|
+
const config = configService.readConfig();
|
|
35
|
+
const pluginOptions = {
|
|
36
|
+
source: options.source || config.source || './src/icons',
|
|
37
|
+
output: options.output || config.output || './src/components/icons',
|
|
38
|
+
framework: options.framework || config.framework || 'react',
|
|
39
|
+
typescript: options.typescript !== undefined ? options.typescript : config.typescript,
|
|
40
|
+
config: options.config || {},
|
|
41
|
+
include: options.include || ['**/*.svg'],
|
|
42
|
+
exclude: options.exclude || ['node_modules/**'],
|
|
43
|
+
exportType: options.exportType || 'default',
|
|
44
|
+
svgo: options.svgo !== undefined ? options.svgo : false,
|
|
45
|
+
generateIndex: options.generateIndex !== undefined ? options.generateIndex : true,
|
|
46
|
+
sourcemap: options.sourcemap !== undefined ? options.sourcemap : false,
|
|
47
|
+
};
|
|
48
|
+
const processedFiles = new Set();
|
|
49
|
+
return {
|
|
50
|
+
name: PLUGIN_NAME,
|
|
51
|
+
async buildStart() {
|
|
52
|
+
logger.info('SVGER Rollup Plugin: Processing SVG files...');
|
|
53
|
+
await processAllSVGs(pluginOptions, processedFiles);
|
|
54
|
+
},
|
|
55
|
+
resolveId(id) {
|
|
56
|
+
// Handle SVG imports
|
|
57
|
+
if (id.endsWith('.svg')) {
|
|
58
|
+
// Let Rollup handle it naturally, we'll transform it
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
async load(id) {
|
|
63
|
+
// Load and transform SVG files
|
|
64
|
+
if (id.endsWith('.svg')) {
|
|
65
|
+
if (await FileSystem.exists(id)) {
|
|
66
|
+
const svgContent = await FileSystem.readFile(id, 'utf-8');
|
|
67
|
+
const componentName = svgProcessor.generateComponentName(id, 'pascal');
|
|
68
|
+
const component = await svgProcessor.generateComponent(componentName, svgContent, {
|
|
69
|
+
framework: pluginOptions.framework,
|
|
70
|
+
typescript: pluginOptions.typescript,
|
|
71
|
+
defaultWidth: config.defaultWidth,
|
|
72
|
+
defaultHeight: config.defaultHeight,
|
|
73
|
+
defaultFill: config.defaultFill,
|
|
74
|
+
styleRules: config.styleRules || {},
|
|
75
|
+
});
|
|
76
|
+
if (pluginOptions.exportType === 'named') {
|
|
77
|
+
return {
|
|
78
|
+
code: `${component}\nexport { ${componentName} };`,
|
|
79
|
+
map: pluginOptions.sourcemap ? { mappings: '' } : null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
code: component,
|
|
84
|
+
map: pluginOptions.sourcemap ? { mappings: '' } : null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
async transform(code, id) {
|
|
90
|
+
// Transform SVG content if loaded by another plugin
|
|
91
|
+
if (id.endsWith('.svg')) {
|
|
92
|
+
const componentName = svgProcessor.generateComponentName(id, 'pascal');
|
|
93
|
+
const component = await svgProcessor.generateComponent(componentName, code, {
|
|
94
|
+
framework: pluginOptions.framework,
|
|
95
|
+
typescript: pluginOptions.typescript,
|
|
96
|
+
defaultWidth: config.defaultWidth,
|
|
97
|
+
defaultHeight: config.defaultHeight,
|
|
98
|
+
defaultFill: config.defaultFill,
|
|
99
|
+
styleRules: config.styleRules || {},
|
|
100
|
+
});
|
|
101
|
+
if (pluginOptions.exportType === 'named') {
|
|
102
|
+
return {
|
|
103
|
+
code: `${component}\nexport { ${componentName} };`,
|
|
104
|
+
map: pluginOptions.sourcemap ? { mappings: '' } : null,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
code: component,
|
|
109
|
+
map: pluginOptions.sourcemap ? { mappings: '' } : null,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Process all SVG files in the source directory
|
|
117
|
+
*/
|
|
118
|
+
async function processAllSVGs(options, processedFiles) {
|
|
119
|
+
const sourceDir = path.resolve(options.source);
|
|
120
|
+
const outputDir = path.resolve(options.output);
|
|
121
|
+
if (!(await FileSystem.exists(sourceDir))) {
|
|
122
|
+
logger.warn(`Source directory not found: ${sourceDir}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
await FileSystem.ensureDir(outputDir);
|
|
126
|
+
const files = await FileSystem.readDir(sourceDir);
|
|
127
|
+
const svgFiles = files.filter((file) => file.endsWith('.svg'));
|
|
128
|
+
if (svgFiles.length === 0) {
|
|
129
|
+
logger.warn('No SVG files found in source directory');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const results = [];
|
|
133
|
+
for (const file of svgFiles) {
|
|
134
|
+
const svgPath = path.join(sourceDir, file);
|
|
135
|
+
const result = await processSVGFile(svgPath, outputDir, options);
|
|
136
|
+
results.push(result);
|
|
137
|
+
if (result.success && result.outputPath) {
|
|
138
|
+
processedFiles.add(result.outputPath);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Generate index file
|
|
142
|
+
if (options.generateIndex) {
|
|
143
|
+
await generateIndexFile(outputDir, results, options);
|
|
144
|
+
}
|
|
145
|
+
const successful = results.filter(r => r.success).length;
|
|
146
|
+
logger.info(`SVGER: Processed ${successful}/${svgFiles.length} SVG files`);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Process a single SVG file
|
|
150
|
+
*/
|
|
151
|
+
async function processSVGFile(svgPath, outputDir, options) {
|
|
152
|
+
try {
|
|
153
|
+
const config = configService.readConfig();
|
|
154
|
+
const mergedConfig = {
|
|
155
|
+
...config,
|
|
156
|
+
...options.config,
|
|
157
|
+
framework: options.framework,
|
|
158
|
+
typescript: options.typescript,
|
|
159
|
+
};
|
|
160
|
+
const result = await svgProcessor.processSVGFile(svgPath, outputDir, {
|
|
161
|
+
framework: mergedConfig.framework,
|
|
162
|
+
typescript: mergedConfig.typescript,
|
|
163
|
+
defaultWidth: mergedConfig.defaultWidth,
|
|
164
|
+
defaultHeight: mergedConfig.defaultHeight,
|
|
165
|
+
defaultFill: mergedConfig.defaultFill,
|
|
166
|
+
styleRules: mergedConfig.styleRules || {},
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
success: result.success,
|
|
170
|
+
outputPath: result.filePath || undefined,
|
|
171
|
+
componentName: result.componentName,
|
|
172
|
+
error: result.error,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
logger.error(`Failed to process ${svgPath}:`, error);
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error: error,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Generate index file with all exports
|
|
185
|
+
*/
|
|
186
|
+
async function generateIndexFile(outputDir, results, options) {
|
|
187
|
+
const extension = options.typescript ? 'ts' : 'js';
|
|
188
|
+
const exports = results
|
|
189
|
+
.filter(r => r.componentName)
|
|
190
|
+
.map(r => `export { default as ${r.componentName} } from './${r.componentName}';`)
|
|
191
|
+
.join('\n');
|
|
192
|
+
const indexPath = path.join(outputDir, `index.${extension}`);
|
|
193
|
+
await FileSystem.writeFile(indexPath, exports, 'utf-8');
|
|
194
|
+
logger.debug(`Generated index file: ${indexPath}`);
|
|
195
|
+
}
|
|
196
|
+
// Default export
|
|
197
|
+
export default svgerRollupPlugin;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Vite Plugin for SVGER-CLI
|
|
3
|
+
*
|
|
4
|
+
* Automatically converts SVG files to framework components during Vite builds
|
|
5
|
+
* with full HMR support and virtual module integration.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```js
|
|
9
|
+
* // vite.config.js
|
|
10
|
+
* import { svgerVitePlugin } from 'svger-cli/vite';
|
|
11
|
+
*
|
|
12
|
+
* export default {
|
|
13
|
+
* plugins: [
|
|
14
|
+
* svgerVitePlugin({
|
|
15
|
+
* source: './src/icons',
|
|
16
|
+
* output: './src/components/icons',
|
|
17
|
+
* framework: 'react',
|
|
18
|
+
* typescript: true
|
|
19
|
+
* })
|
|
20
|
+
* ]
|
|
21
|
+
* };
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import type { VitePluginOptions } from '../types/integrations.js';
|
|
25
|
+
/**
|
|
26
|
+
* Vite Plugin for SVGER-CLI
|
|
27
|
+
*/
|
|
28
|
+
export declare function svgerVitePlugin(options?: VitePluginOptions): any;
|
|
29
|
+
export default svgerVitePlugin;
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Vite Plugin for SVGER-CLI
|
|
3
|
+
*
|
|
4
|
+
* Automatically converts SVG files to framework components during Vite builds
|
|
5
|
+
* with full HMR support and virtual module integration.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```js
|
|
9
|
+
* // vite.config.js
|
|
10
|
+
* import { svgerVitePlugin } from 'svger-cli/vite';
|
|
11
|
+
*
|
|
12
|
+
* export default {
|
|
13
|
+
* plugins: [
|
|
14
|
+
* svgerVitePlugin({
|
|
15
|
+
* source: './src/icons',
|
|
16
|
+
* output: './src/components/icons',
|
|
17
|
+
* framework: 'react',
|
|
18
|
+
* typescript: true
|
|
19
|
+
* })
|
|
20
|
+
* ]
|
|
21
|
+
* };
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import path from 'path';
|
|
25
|
+
import { FileSystem } from '../utils/native.js';
|
|
26
|
+
import { svgProcessor } from '../processors/svg-processor.js';
|
|
27
|
+
import { configService } from '../services/config.js';
|
|
28
|
+
import { logger } from '../core/logger.js';
|
|
29
|
+
const PLUGIN_NAME = 'svger-vite-plugin';
|
|
30
|
+
const VIRTUAL_MODULE_PREFIX = 'virtual:svger/';
|
|
31
|
+
/**
|
|
32
|
+
* Vite Plugin for SVGER-CLI
|
|
33
|
+
*/
|
|
34
|
+
export function svgerVitePlugin(options = {}) {
|
|
35
|
+
const config = configService.readConfig();
|
|
36
|
+
const pluginOptions = {
|
|
37
|
+
source: options.source || config.source || './src/icons',
|
|
38
|
+
output: options.output || config.output || './src/components/icons',
|
|
39
|
+
framework: options.framework || config.framework || 'react',
|
|
40
|
+
typescript: options.typescript !== undefined ? options.typescript : config.typescript,
|
|
41
|
+
config: options.config || {},
|
|
42
|
+
include: options.include || ['**/*.svg'],
|
|
43
|
+
exclude: options.exclude || ['node_modules/**'],
|
|
44
|
+
hmr: options.hmr !== undefined ? options.hmr : true,
|
|
45
|
+
virtual: options.virtual !== undefined ? options.virtual : false,
|
|
46
|
+
exportType: options.exportType || 'default',
|
|
47
|
+
svgo: options.svgo !== undefined ? options.svgo : false,
|
|
48
|
+
generateIndex: options.generateIndex !== undefined ? options.generateIndex : true,
|
|
49
|
+
};
|
|
50
|
+
let viteConfig;
|
|
51
|
+
const processedFiles = new Set();
|
|
52
|
+
return {
|
|
53
|
+
name: PLUGIN_NAME,
|
|
54
|
+
configResolved(resolvedConfig) {
|
|
55
|
+
viteConfig = resolvedConfig;
|
|
56
|
+
},
|
|
57
|
+
async buildStart() {
|
|
58
|
+
logger.info('SVGER Vite Plugin: Processing SVG files...');
|
|
59
|
+
await processAllSVGs(pluginOptions, processedFiles);
|
|
60
|
+
},
|
|
61
|
+
async handleHotUpdate(ctx) {
|
|
62
|
+
if (!pluginOptions.hmr)
|
|
63
|
+
return;
|
|
64
|
+
const { file, server } = ctx;
|
|
65
|
+
if (file.endsWith('.svg') && file.includes(pluginOptions.source)) {
|
|
66
|
+
logger.info(`SVGER: Hot reloading ${path.basename(file)}`);
|
|
67
|
+
const outputDir = path.resolve(pluginOptions.output);
|
|
68
|
+
const result = await processSVGFile(file, outputDir, pluginOptions);
|
|
69
|
+
if (result.success) {
|
|
70
|
+
// Trigger HMR for the generated component
|
|
71
|
+
const modules = server.moduleGraph.getModulesByFile(file);
|
|
72
|
+
if (modules) {
|
|
73
|
+
return Array.from(modules);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
resolveId(id) {
|
|
79
|
+
// Handle virtual modules
|
|
80
|
+
if (pluginOptions.virtual && id.startsWith(VIRTUAL_MODULE_PREFIX)) {
|
|
81
|
+
return '\0' + id;
|
|
82
|
+
}
|
|
83
|
+
// Handle direct SVG imports
|
|
84
|
+
if (id.endsWith('.svg')) {
|
|
85
|
+
return null; // Let Vite handle it with our transform hook
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
async load(id) {
|
|
89
|
+
// Handle virtual modules
|
|
90
|
+
if (pluginOptions.virtual &&
|
|
91
|
+
id.startsWith('\0' + VIRTUAL_MODULE_PREFIX)) {
|
|
92
|
+
const svgName = id.slice(('\0' + VIRTUAL_MODULE_PREFIX).length);
|
|
93
|
+
const sourceDir = path.resolve(pluginOptions.source);
|
|
94
|
+
const svgPath = path.join(sourceDir, svgName + '.svg');
|
|
95
|
+
if (await FileSystem.exists(svgPath)) {
|
|
96
|
+
const svgContent = await FileSystem.readFile(svgPath, 'utf-8');
|
|
97
|
+
const componentName = svgProcessor.generateComponentName(svgPath, 'pascal');
|
|
98
|
+
const component = await svgProcessor.generateComponent(componentName, svgContent, {
|
|
99
|
+
framework: pluginOptions.framework,
|
|
100
|
+
typescript: pluginOptions.typescript,
|
|
101
|
+
defaultWidth: config.defaultWidth,
|
|
102
|
+
defaultHeight: config.defaultHeight,
|
|
103
|
+
defaultFill: config.defaultFill,
|
|
104
|
+
styleRules: config.styleRules || {},
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
code: component,
|
|
108
|
+
map: null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
async transform(code, id) {
|
|
114
|
+
// Transform direct SVG imports
|
|
115
|
+
if (id.endsWith('.svg')) {
|
|
116
|
+
const componentName = svgProcessor.generateComponentName(id, 'pascal');
|
|
117
|
+
const component = await svgProcessor.generateComponent(componentName, code, {
|
|
118
|
+
framework: pluginOptions.framework,
|
|
119
|
+
typescript: pluginOptions.typescript,
|
|
120
|
+
defaultWidth: config.defaultWidth,
|
|
121
|
+
defaultHeight: config.defaultHeight,
|
|
122
|
+
defaultFill: config.defaultFill,
|
|
123
|
+
styleRules: config.styleRules || {},
|
|
124
|
+
});
|
|
125
|
+
if (pluginOptions.exportType === 'named') {
|
|
126
|
+
return {
|
|
127
|
+
code: `${component}\nexport { ${componentName} };`,
|
|
128
|
+
map: null,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
code: component,
|
|
133
|
+
map: null,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Process all SVG files in the source directory
|
|
141
|
+
*/
|
|
142
|
+
async function processAllSVGs(options, processedFiles) {
|
|
143
|
+
const sourceDir = path.resolve(options.source);
|
|
144
|
+
const outputDir = path.resolve(options.output);
|
|
145
|
+
if (!(await FileSystem.exists(sourceDir))) {
|
|
146
|
+
logger.warn(`Source directory not found: ${sourceDir}`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
await FileSystem.ensureDir(outputDir);
|
|
150
|
+
const files = await FileSystem.readDir(sourceDir);
|
|
151
|
+
const svgFiles = files.filter((file) => file.endsWith('.svg'));
|
|
152
|
+
if (svgFiles.length === 0) {
|
|
153
|
+
logger.warn('No SVG files found in source directory');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const results = [];
|
|
157
|
+
for (const file of svgFiles) {
|
|
158
|
+
const svgPath = path.join(sourceDir, file);
|
|
159
|
+
const result = await processSVGFile(svgPath, outputDir, options);
|
|
160
|
+
results.push(result);
|
|
161
|
+
if (result.success && result.outputPath) {
|
|
162
|
+
processedFiles.add(result.outputPath);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Generate index file
|
|
166
|
+
if (options.generateIndex) {
|
|
167
|
+
await generateIndexFile(outputDir, results, options);
|
|
168
|
+
}
|
|
169
|
+
const successful = results.filter(r => r.success).length;
|
|
170
|
+
logger.info(`SVGER: Processed ${successful}/${svgFiles.length} SVG files`);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Process a single SVG file
|
|
174
|
+
*/
|
|
175
|
+
async function processSVGFile(svgPath, outputDir, options) {
|
|
176
|
+
try {
|
|
177
|
+
const config = configService.readConfig();
|
|
178
|
+
const mergedConfig = {
|
|
179
|
+
...config,
|
|
180
|
+
...options.config,
|
|
181
|
+
framework: options.framework,
|
|
182
|
+
typescript: options.typescript,
|
|
183
|
+
};
|
|
184
|
+
const result = await svgProcessor.processSVGFile(svgPath, outputDir, {
|
|
185
|
+
framework: mergedConfig.framework,
|
|
186
|
+
typescript: mergedConfig.typescript,
|
|
187
|
+
defaultWidth: mergedConfig.defaultWidth,
|
|
188
|
+
defaultHeight: mergedConfig.defaultHeight,
|
|
189
|
+
defaultFill: mergedConfig.defaultFill,
|
|
190
|
+
styleRules: mergedConfig.styleRules || {},
|
|
191
|
+
});
|
|
192
|
+
return {
|
|
193
|
+
success: result.success,
|
|
194
|
+
outputPath: result.filePath || undefined,
|
|
195
|
+
componentName: result.componentName,
|
|
196
|
+
error: result.error,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
logger.error(`Failed to process ${svgPath}:`, error);
|
|
201
|
+
return {
|
|
202
|
+
success: false,
|
|
203
|
+
error: error,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Generate index file with all exports
|
|
209
|
+
*/
|
|
210
|
+
async function generateIndexFile(outputDir, results, options) {
|
|
211
|
+
const extension = options.typescript ? 'ts' : 'js';
|
|
212
|
+
const exports = results
|
|
213
|
+
.filter(r => r.componentName)
|
|
214
|
+
.map(r => `export { default as ${r.componentName} } from './${r.componentName}';`)
|
|
215
|
+
.join('\n');
|
|
216
|
+
const indexPath = path.join(outputDir, `index.${extension}`);
|
|
217
|
+
await FileSystem.writeFile(indexPath, exports, 'utf-8');
|
|
218
|
+
logger.debug(`Generated index file: ${indexPath}`);
|
|
219
|
+
}
|
|
220
|
+
// Default export
|
|
221
|
+
export default svgerVitePlugin;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Webpack Plugin for SVGER-CLI
|
|
3
|
+
*
|
|
4
|
+
* Automatically converts SVG files to framework components during webpack builds
|
|
5
|
+
* with full HMR support and optimization.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```js
|
|
9
|
+
* // webpack.config.js
|
|
10
|
+
* const { SvgerWebpackPlugin } = require('svger-cli/webpack');
|
|
11
|
+
*
|
|
12
|
+
* module.exports = {
|
|
13
|
+
* plugins: [
|
|
14
|
+
* new SvgerWebpackPlugin({
|
|
15
|
+
* source: './src/icons',
|
|
16
|
+
* output: './src/components/icons',
|
|
17
|
+
* framework: 'react',
|
|
18
|
+
* typescript: true
|
|
19
|
+
* })
|
|
20
|
+
* ]
|
|
21
|
+
* };
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import type { WebpackPluginOptions } from '../types/integrations.js';
|
|
25
|
+
/**
|
|
26
|
+
* Webpack Plugin for SVGER-CLI
|
|
27
|
+
*/
|
|
28
|
+
export declare class SvgerWebpackPlugin {
|
|
29
|
+
private options;
|
|
30
|
+
private processedFiles;
|
|
31
|
+
private watchDebounceTimer?;
|
|
32
|
+
constructor(options?: WebpackPluginOptions);
|
|
33
|
+
apply(compiler: any): void;
|
|
34
|
+
/**
|
|
35
|
+
* Process all SVG files in the source directory
|
|
36
|
+
*/
|
|
37
|
+
private processAllSVGs;
|
|
38
|
+
/**
|
|
39
|
+
* Process changed files in watch mode
|
|
40
|
+
*/
|
|
41
|
+
private processChangedFiles;
|
|
42
|
+
/**
|
|
43
|
+
* Process a single SVG file
|
|
44
|
+
*/
|
|
45
|
+
private processSVGFile;
|
|
46
|
+
/**
|
|
47
|
+
* Generate index file with all exports
|
|
48
|
+
*/
|
|
49
|
+
private generateIndexFile;
|
|
50
|
+
/**
|
|
51
|
+
* Get changed files from webpack
|
|
52
|
+
*/
|
|
53
|
+
private getChangedFiles;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Webpack Loader for SVGER-CLI
|
|
57
|
+
*
|
|
58
|
+
* Transforms SVG imports into framework components inline
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```js
|
|
62
|
+
* // webpack.config.js
|
|
63
|
+
* module.exports = {
|
|
64
|
+
* module: {
|
|
65
|
+
* rules: [
|
|
66
|
+
* {
|
|
67
|
+
* test: /\.svg$/,
|
|
68
|
+
* use: [
|
|
69
|
+
* {
|
|
70
|
+
* loader: 'svger-cli/webpack-loader',
|
|
71
|
+
* options: {
|
|
72
|
+
* framework: 'react',
|
|
73
|
+
* typescript: true
|
|
74
|
+
* }
|
|
75
|
+
* }
|
|
76
|
+
* ]
|
|
77
|
+
* }
|
|
78
|
+
* ]
|
|
79
|
+
* }
|
|
80
|
+
* };
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function svgerLoader(this: any, content: string): Promise<string>;
|
|
84
|
+
export default SvgerWebpackPlugin;
|