@blocklet/pages-kit-block-studio 0.4.104 → 0.4.106

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.
@@ -56,8 +56,13 @@ const vite_plugin_node_polyfills_1 = require("vite-plugin-node-polyfills");
56
56
  const vite_plugin_react_pages_1 = __importStar(require("vite-plugin-react-pages"));
57
57
  const helper_1 = require("../utils/helper");
58
58
  const vite_plugin_html_transform_1 = require("./vite-plugin-html-transform");
59
+ const vite_plugin_import_transform_1 = require("./vite-plugin-import-transform");
59
60
  // const BUILTIN_MODULES_VAR = '__PAGES_KIT_BUILTIN_MODULES__';
60
61
  // logger.log('BUILTIN_MODULES_VAR', BUILTIN_MODULES_VAR);
62
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
63
+ const isMatchAfterSlachExternals = (_id) => {
64
+ return false;
65
+ };
61
66
  const defaultBlockExternals = {
62
67
  // 核心 React 相关
63
68
  react: '@blocklet/pages-kit/builtin/react',
@@ -90,6 +95,19 @@ const defaultBlockExternals = {
90
95
  'react-scroll-to-bottom': '@blocklet/pages-kit/builtin/async/react-scroll-to-bottom',
91
96
  '@blocklet/pages-kit': '@blocklet/pages-kit',
92
97
  };
98
+ const importTransformConfig = {
99
+ transforms: [
100
+ {
101
+ find: [
102
+ // import {useTheme} from '@mui/material/styles' => import {useTheme} from '@mui/material'
103
+ { source: '@mui/material/styles', type: 'ImportSpecifier' },
104
+ // import useTheme from '@mui/material/styles/useTheme' => import { useTheme } from '@mui/material'
105
+ { source: '@mui/material/styles/*', type: 'ImportDefaultSpecifier' },
106
+ ],
107
+ replace: { source: '@mui/material', type: 'ImportSpecifier' },
108
+ },
109
+ ],
110
+ };
93
111
  function initBlockStudioPlugins(options) {
94
112
  const workingDir = options?.cwd || process.cwd();
95
113
  const entryFilesPattern = options?.entryFilesPattern || (0, helper_1.getBlockEntryFilesPattern)();
@@ -162,6 +180,7 @@ function initBlockStudioPlugins(options) {
162
180
  // return html;
163
181
  // },
164
182
  // },
183
+ (0, vite_plugin_import_transform_1.importTransformPlugin)(importTransformConfig),
165
184
  options?.ignoreNodePolyfills
166
185
  ? undefined
167
186
  : (0, vite_plugin_node_polyfills_1.nodePolyfills)({
@@ -205,7 +224,7 @@ function initBlockStudioPlugins(options) {
205
224
  external: _config?.build?.rollupOptions?.external ||
206
225
  ((id) => {
207
226
  // 是否匹配后缀
208
- const isMatchAfterSlash = false;
227
+ const isMatchAfterSlash = isMatchAfterSlachExternals(id);
209
228
  const skipList = [...Object.keys(externalMappings)];
210
229
  if (skipList.some((item) => (isMatchAfterSlash && id.startsWith(`${item}/`)) || id === item)) {
211
230
  return true;
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.importTransformPlugin = importTransformPlugin;
37
+ const ts = __importStar(require("typescript"));
38
+ /**
39
+ * 简化版的 import 转换 Vite 插件
40
+ * 用于在构建过程中修改导入语句的源路径和类型
41
+ */
42
+ function importTransformPlugin(options = {}) {
43
+ const { transforms = [], include = /\.[jt]sx?$/, exclude = /node_modules/ } = options;
44
+ // 创建过滤函数,判断是否应处理该文件
45
+ const filter = (id) => {
46
+ // 排除 node_modules 目录
47
+ if (id.includes('node_modules'))
48
+ return false;
49
+ // 处理 include 规则
50
+ const testInclude = (pattern) => {
51
+ if (typeof pattern === 'string')
52
+ return id.includes(pattern);
53
+ return pattern.test(id);
54
+ };
55
+ // 处理 exclude 规则
56
+ const testExclude = (pattern) => {
57
+ if (typeof pattern === 'string')
58
+ return id.includes(pattern);
59
+ return pattern.test(id);
60
+ };
61
+ // 检查是否符合 include 规则
62
+ const shouldInclude = Array.isArray(include) ? include.some(testInclude) : testInclude(include);
63
+ // 检查是否符合 exclude 规则
64
+ const shouldExclude = Array.isArray(exclude) ? exclude.some(testExclude) : testExclude(exclude);
65
+ return shouldInclude && !shouldExclude;
66
+ };
67
+ return {
68
+ name: 'import-transform',
69
+ transform(code, id) {
70
+ // 如果不需要处理该文件,直接返回
71
+ if (!filter(id))
72
+ return null;
73
+ // 使用 TypeScript 解析源代码
74
+ const sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
75
+ // 记录是否有改变
76
+ let hasChanged = false;
77
+ // 创建转换器
78
+ const transformer = (context) => {
79
+ const visit = (node) => {
80
+ // 仅处理导入声明
81
+ if (ts.isImportDeclaration(node)) {
82
+ const importPath = getImportPath(node);
83
+ if (!importPath)
84
+ return ts.visitEachChild(node, visit, context);
85
+ const importType = getImportType(node);
86
+ // 记录是否找到匹配的规则
87
+ let matched = false;
88
+ // 遍历所有转换规则
89
+ for (const transform of transforms) {
90
+ const finds = Array.isArray(transform.find) ? transform.find : [transform.find];
91
+ // 检查每个查找条件
92
+ for (const find of finds) {
93
+ // 检查源路径和导入类型是否匹配
94
+ if (!matchSourcePath(find.source, importPath)) {
95
+ // 路径不匹配,检查下一条
96
+ }
97
+ else if (find.type && find.type !== importType) {
98
+ // 类型不匹配,检查下一条
99
+ }
100
+ else {
101
+ // 找到匹配的导入声明
102
+ matched = true;
103
+ hasChanged = true;
104
+ const replacePath = transform.replace.source;
105
+ const replaceType = transform.replace.type;
106
+ // 如果指定了替换类型
107
+ if (replaceType && replaceType !== importType) {
108
+ // 处理不同类型的导入转换
109
+ if (importType === 'ImportSpecifier' && replaceType === 'ImportDefaultSpecifier') {
110
+ // { X } -> default
111
+ const names = node.importClause?.namedBindings;
112
+ if (!names || !names.elements[0])
113
+ return ts.visitEachChild(node, visit, context);
114
+ const importName = names.elements[0].name.text;
115
+ return createDefaultImport(importName, replacePath);
116
+ }
117
+ if (importType === 'ImportDefaultSpecifier' && replaceType === 'ImportNamespaceSpecifier') {
118
+ // default -> * as X
119
+ const name = node.importClause?.name?.text;
120
+ if (!name)
121
+ return ts.visitEachChild(node, visit, context);
122
+ return createNamespaceImport(name, replacePath);
123
+ }
124
+ if (importType === 'ImportNamespaceSpecifier' && replaceType === 'ImportDefaultSpecifier') {
125
+ // * as X -> default
126
+ const binding = node.importClause?.namedBindings;
127
+ if (!binding)
128
+ return ts.visitEachChild(node, visit, context);
129
+ const name = binding.name.text;
130
+ return createDefaultImport(name, replacePath);
131
+ }
132
+ if (importType === 'ImportDefaultSpecifier' && replaceType === 'ImportSpecifier') {
133
+ // default -> { X }
134
+ const name = node.importClause?.name?.text;
135
+ if (!name)
136
+ return ts.visitEachChild(node, visit, context);
137
+ // 智能处理:检测是否需要使用别名
138
+ // 从路径中提取原始名称,如 '@mui/material/styles/useTheme' -> 'useTheme'
139
+ const originalName = extractNameFromPath(importPath);
140
+ // 如果能从路径中提取名称,使用它作为原始名称
141
+ if (originalName && originalName !== name) {
142
+ return createNamedImportWithAlias(originalName, name, replacePath);
143
+ }
144
+ // 退回到简单导入
145
+ return createNamedImport(name, replacePath);
146
+ }
147
+ }
148
+ else {
149
+ // 没有指定替换类型,智能推断最合适的转换
150
+ // 默认导入 -> 命名导入的智能转换(基于路径分析)
151
+ const isDefaultImport = importType === 'ImportDefaultSpecifier';
152
+ if (isDefaultImport && isComponentPath(importPath)) {
153
+ const name = node.importClause?.name?.text;
154
+ if (!name)
155
+ return ts.visitEachChild(node, visit, context);
156
+ // 从路径中提取组件名称
157
+ const componentName = extractNameFromPath(importPath);
158
+ if (componentName && componentName !== name) {
159
+ // 使用从路径中提取的组件名作为原始导入名
160
+ return createNamedImportWithAlias(componentName, name, replacePath);
161
+ }
162
+ }
163
+ }
164
+ // 只改变导入路径
165
+ if (replacePath !== importPath) {
166
+ return ts.factory.createImportDeclaration(undefined, node.importClause, ts.factory.createStringLiteral(replacePath));
167
+ }
168
+ // 找到匹配但无需转换,继续检查下一个规则
169
+ break;
170
+ }
171
+ }
172
+ // 如果已经找到匹配并转换了,就不再继续检查
173
+ if (matched)
174
+ break;
175
+ }
176
+ }
177
+ return ts.visitEachChild(node, visit, context);
178
+ };
179
+ return (node) => ts.visitNode(node, visit);
180
+ };
181
+ // 应用转换
182
+ const result = ts.transform(sourceFile, [transformer]);
183
+ // 如果有改变,打印转换后的代码
184
+ if (hasChanged) {
185
+ const printer = ts.createPrinter();
186
+ const transformedCode = printer.printFile(result.transformed[0]);
187
+ return { code: transformedCode };
188
+ }
189
+ // 没有变化,返回 null
190
+ return null;
191
+ },
192
+ };
193
+ }
194
+ exports.default = importTransformPlugin;
195
+ // 辅助函数:获取导入路径
196
+ function getImportPath(node) {
197
+ const { moduleSpecifier } = node;
198
+ if (ts.isStringLiteral(moduleSpecifier)) {
199
+ return moduleSpecifier.text;
200
+ }
201
+ return undefined;
202
+ }
203
+ // 辅助函数:获取导入类型
204
+ function getImportType(node) {
205
+ if (node.importClause) {
206
+ if (node.importClause.name) {
207
+ return 'ImportDefaultSpecifier';
208
+ }
209
+ if (node.importClause.namedBindings) {
210
+ if (ts.isNamespaceImport(node.importClause.namedBindings)) {
211
+ return 'ImportNamespaceSpecifier';
212
+ }
213
+ if (ts.isNamedImports(node.importClause.namedBindings)) {
214
+ return 'ImportSpecifier';
215
+ }
216
+ }
217
+ }
218
+ return '';
219
+ }
220
+ // 辅助函数:创建默认导入
221
+ function createDefaultImport(name, path) {
222
+ return ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, ts.factory.createIdentifier(name), undefined), ts.factory.createStringLiteral(path));
223
+ }
224
+ // 辅助函数:创建命名空间导入
225
+ function createNamespaceImport(name, path) {
226
+ return ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamespaceImport(ts.factory.createIdentifier(name))), ts.factory.createStringLiteral(path));
227
+ }
228
+ // 辅助函数:创建命名导入
229
+ function createNamedImport(name, path) {
230
+ return ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports([
231
+ ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(name)),
232
+ ])), ts.factory.createStringLiteral(path));
233
+ }
234
+ // 辅助函数:从路径中提取名称
235
+ function extractNameFromPath(path) {
236
+ // 处理类似 '@mui/material/styles/useTheme' 的路径
237
+ const segments = path.split('/');
238
+ const lastSegment = segments[segments.length - 1];
239
+ // 如果最后一段有意义的名称(不是index或为空),返回它
240
+ if (lastSegment && lastSegment !== 'index') {
241
+ return lastSegment;
242
+ }
243
+ return undefined;
244
+ }
245
+ // 辅助函数:创建带别名的命名导入
246
+ function createNamedImportWithAlias(originalName, aliasName, path) {
247
+ return ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports([
248
+ ts.factory.createImportSpecifier(false, ts.factory.createIdentifier(originalName), ts.factory.createIdentifier(aliasName)),
249
+ ])), ts.factory.createStringLiteral(path));
250
+ }
251
+ // 辅助函数:检查是否是组件路径(含有组件名的子路径)
252
+ function isComponentPath(path) {
253
+ // 检查路径是否包含至少一个斜杠,且最后一段不是index
254
+ const segments = path.split('/');
255
+ return segments.length > 1 && segments[segments.length - 1] !== 'index';
256
+ }
257
+ // 辅助函数:检查源路径是否匹配(支持通配符)
258
+ function matchSourcePath(pattern, actualPath) {
259
+ // 处理精确匹配
260
+ if (pattern === actualPath)
261
+ return true;
262
+ // 处理通配符匹配
263
+ if (pattern.endsWith('/*')) {
264
+ const basePath = pattern.slice(0, -2); // 移除 '/*'
265
+ return actualPath.startsWith(`${basePath}/`);
266
+ }
267
+ // 可以在这里添加更多匹配逻辑,如正则表达式
268
+ return false;
269
+ }