@shellui/cli 0.0.19 → 0.0.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shellui/cli",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "ShellUI CLI - Command-line tool for ShellUI",
5
5
  "main": "src/cli.js",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "tsx": "^4.21.0",
31
31
  "vite": "7.3.1",
32
32
  "workbox-build": "^7.1.0",
33
- "@shellui/core": "0.0.19"
33
+ "@shellui/core": "0.0.21"
34
34
  },
35
35
  "publishConfig": {
36
36
  "access": "public"
@@ -11,6 +11,8 @@ import {
11
11
  createViteDefine,
12
12
  createViteResolveConfig,
13
13
  createViteOptimizeDepsConfig,
14
+ getDedupeList,
15
+ getShelluiExcludePackages,
14
16
  resolvePackagePath,
15
17
  } from '../utils/index.js';
16
18
  import { serviceWorkerDevPlugin } from '../utils/service-worker-plugin.js';
@@ -20,6 +22,74 @@ let configWatcher = null;
20
22
  let restartTimeout = null;
21
23
  let isFirstStart = true;
22
24
 
25
+ /**
26
+ * Plugin to prevent Vite from creating cache files inside @shellui/core
27
+ * This ensures all cache is created only in the project root's node_modules/.vite
28
+ */
29
+ function preventNestedCachePlugin(viteCacheDir) {
30
+ return {
31
+ name: 'prevent-nested-cache',
32
+ configResolved(config) {
33
+ if (config.cacheDir && !path.isAbsolute(config.cacheDir)) {
34
+ throw new Error(
35
+ `cacheDir must be absolute path, got: ${config.cacheDir}. This prevents cache creation inside @shellui/core`,
36
+ );
37
+ }
38
+ },
39
+ buildStart() {
40
+ // Check if any .vite directories exist inside @shellui/core and warn/remove them
41
+ const corePackagePath = resolvePackagePath('@shellui/core');
42
+ const nestedViteCache = path.join(corePackagePath, 'node_modules', '.vite');
43
+ if (fs.existsSync(nestedViteCache)) {
44
+ console.warn(
45
+ pc.yellow(
46
+ `⚠️ Found nested .vite cache at ${nestedViteCache}. This should not exist. Removing...`,
47
+ ),
48
+ );
49
+ try {
50
+ fs.rmSync(nestedViteCache, { recursive: true, force: true });
51
+ console.log(pc.green(`✅ Removed nested cache directory`));
52
+ } catch (e) {
53
+ console.error(pc.red(`❌ Failed to remove nested cache: ${e.message}`));
54
+ }
55
+ }
56
+
57
+ // Also remove any optimized @shellui/core files from .vite/deps
58
+ const viteDepsDir = path.join(viteCacheDir, 'deps');
59
+ if (fs.existsSync(viteDepsDir)) {
60
+ try {
61
+ const files = fs.readdirSync(viteDepsDir);
62
+ const shelluiFiles = files.filter(
63
+ (f) => f.startsWith('@shellui') || f.startsWith('@_features'),
64
+ );
65
+ if (shelluiFiles.length > 0) {
66
+ console.warn(
67
+ pc.yellow(
68
+ `⚠️ Found optimized @shellui/core files in .vite/deps. Removing ${shelluiFiles.length} files...`,
69
+ ),
70
+ );
71
+ shelluiFiles.forEach((file) => {
72
+ const filePath = path.join(viteDepsDir, file);
73
+ try {
74
+ fs.unlinkSync(filePath);
75
+ const mapPath = filePath + '.map';
76
+ if (fs.existsSync(mapPath)) {
77
+ fs.unlinkSync(mapPath);
78
+ }
79
+ } catch (e) {
80
+ // Ignore errors
81
+ }
82
+ });
83
+ console.log(pc.green(`✅ Removed optimized @shellui/core files`));
84
+ }
85
+ } catch (e) {
86
+ // Ignore errors reading directory
87
+ }
88
+ }
89
+ },
90
+ };
91
+ }
92
+
23
93
  /**
24
94
  * Start the Vite server with current configuration
25
95
  * @param {string} root - Root directory
@@ -35,6 +105,12 @@ async function startServer(root, cwd, shouldOpen = false) {
35
105
  const corePackagePath = resolvePackagePath('@shellui/core');
36
106
  const coreSrcPath = getCoreSrcPath();
37
107
 
108
+ // Get project root node_modules path to ensure all modules resolve from root
109
+ const projectRootNodeModules = path.resolve(cwd, root, 'node_modules');
110
+ // CRITICAL: Set cacheDir to absolute path in project root to prevent Vite from creating
111
+ // cache inside @shellui/core/node_modules/.vite/deps
112
+ const viteCacheDir = path.resolve(cwd, root, 'node_modules', '.vite');
113
+
38
114
  // Check if static folder exists in project root
39
115
  const staticPath = path.resolve(cwd, root, 'static');
40
116
  const publicDir = fs.existsSync(staticPath) ? staticPath : false;
@@ -44,13 +120,100 @@ async function startServer(root, cwd, shouldOpen = false) {
44
120
 
45
121
  const server = await createServer({
46
122
  root: coreSrcPath,
47
- plugins: [react(), serviceWorkerDevPlugin(corePackagePath, coreSrcPath)],
123
+ // Force cacheDir to project root - this prevents Vite from creating cache
124
+ // relative to root (which would be inside @shellui/core)
125
+ cacheDir: viteCacheDir,
126
+ plugins: [
127
+ react(),
128
+ serviceWorkerDevPlugin(corePackagePath, coreSrcPath),
129
+ preventNestedCachePlugin(viteCacheDir),
130
+ {
131
+ name: 'prevent-shellui-optimization',
132
+ enforce: 'pre',
133
+ config(config) {
134
+ if (!config.optimizeDeps) {
135
+ config.optimizeDeps = {};
136
+ }
137
+ const originalExclude = config.optimizeDeps.exclude || [];
138
+ const excludeArray = Array.isArray(originalExclude)
139
+ ? [...originalExclude]
140
+ : [originalExclude].filter(Boolean);
141
+
142
+ // Dynamically get all @shellui/* packages that should be excluded
143
+ const shelluiExcludePackages = getShelluiExcludePackages();
144
+ shelluiExcludePackages.forEach((pkg) => {
145
+ if (!excludeArray.includes(pkg)) {
146
+ excludeArray.push(pkg);
147
+ }
148
+ });
149
+
150
+ config.optimizeDeps.exclude = excludeArray;
151
+ },
152
+ resolveId(id, importer) {
153
+ if (id && typeof id === 'string') {
154
+ if (id.includes('@_features') || id.includes('@shellui/core/src/')) {
155
+ return null;
156
+ }
157
+ }
158
+ return null;
159
+ },
160
+ load(id) {
161
+ if (id && typeof id === 'string' && id.includes('@_features')) {
162
+ return null;
163
+ }
164
+ return null;
165
+ },
166
+ transform(code, id) {
167
+ if (
168
+ id &&
169
+ typeof id === 'string' &&
170
+ (id.includes('@shellui/core/src/') || id.includes('@_features'))
171
+ ) {
172
+ return null;
173
+ }
174
+ return null;
175
+ },
176
+ configureServer(server) {
177
+ server.middlewares.use((req, res, next) => {
178
+ if (
179
+ req.url &&
180
+ (req.url.includes('@_features') || req.url.includes('/.vite/deps/@shellui'))
181
+ ) {
182
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
183
+ res.end(
184
+ 'Optimized @shellui/core files are disabled. Loading from source instead.',
185
+ );
186
+ return;
187
+ }
188
+ next();
189
+ });
190
+ },
191
+ },
192
+ ],
48
193
  define: createViteDefine(config),
49
194
  resolve: {
50
195
  ...resolveConfig,
51
- alias: resolveAlias,
196
+ // Dynamically dedupe React, ReactDOM, @shellui packages, and all @shellui/core dependencies
197
+ // This ensures all modules resolve from project root to prevent duplicate instances
198
+ dedupe: getDedupeList(),
199
+ preserveSymlinks: false,
200
+ alias: {
201
+ ...resolveAlias,
202
+ // Force @shellui/core to always resolve from project root to prevent duplicates
203
+ '@shellui/core': corePackagePath,
204
+ },
205
+ conditions: ['import', 'module', 'browser', 'default'],
206
+ mainFields: ['browser', 'module', 'jsnext:main', 'jsnext', 'main'],
207
+ },
208
+ optimizeDeps: {
209
+ // Dynamically exclude @shellui packages and include all @shellui/core dependencies
210
+ // This ensures dependencies are optimized from project root, preventing nested resolution
211
+ ...createViteOptimizeDepsConfig(),
212
+ force: false,
213
+ esbuildOptions: {
214
+ absWorkingDir: path.resolve(cwd, root),
215
+ },
52
216
  },
53
- optimizeDeps: createViteOptimizeDepsConfig(),
54
217
  css: {
55
218
  postcss: createPostCSSConfig(),
56
219
  },
@@ -14,4 +14,6 @@ export {
14
14
  createViteDefine,
15
15
  createViteResolveConfig,
16
16
  createViteOptimizeDepsConfig,
17
+ getDedupeList,
18
+ getShelluiExcludePackages,
17
19
  } from './vite.js';
package/src/utils/vite.js CHANGED
@@ -41,12 +41,9 @@ export function getCoreSrcPath() {
41
41
  * @returns {Object} Vite resolve.alias object
42
42
  */
43
43
  export function createResolveAlias() {
44
- const corePackagePath = resolvePackagePath('@shellui/core');
45
44
  const sdkEntry = resolveSdkEntry();
46
45
 
47
- const alias = {
48
- '@': path.join(corePackagePath, 'src'),
49
- };
46
+ const alias = {};
50
47
 
51
48
  if (sdkEntry) {
52
49
  alias['@shellui/sdk'] = sdkEntry;
@@ -106,25 +103,122 @@ export function createViteDefine(config) {
106
103
  * Create Vite resolve configuration with deduplication.
107
104
  * Prevents duplicate React instances and @shellui/core modules when running
108
105
  * from node_modules, which can cause context provider issues in microfrontends.
106
+ *
107
+ * Dynamically includes all @shellui/core dependencies to ensure they resolve
108
+ * from project root, preventing nested node_modules resolution issues.
109
109
  * @returns {Object} Vite resolve configuration with dedupe
110
110
  */
111
111
  export function createViteResolveConfig() {
112
112
  return {
113
- dedupe: ['react', 'react-dom', '@shellui/core'],
113
+ dedupe: getDedupeList(),
114
114
  };
115
115
  }
116
116
 
117
+ /**
118
+ * Get dependencies from @shellui/core package.json
119
+ * Reads the package.json and extracts all dependencies (excluding @shellui/* packages)
120
+ * @returns {string[]} Array of dependency package names
121
+ */
122
+ function getCoreDependencies() {
123
+ try {
124
+ const corePackagePath = resolvePackagePath('@shellui/core');
125
+ const packageJsonPath = path.join(corePackagePath, 'package.json');
126
+
127
+ if (!fs.existsSync(packageJsonPath)) {
128
+ console.warn(`Warning: Could not find @shellui/core package.json at ${packageJsonPath}`);
129
+ return [];
130
+ }
131
+
132
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
133
+ const dependencies = packageJson.dependencies || {};
134
+
135
+ // Extract all dependency names, excluding @shellui/* packages
136
+ return Object.keys(dependencies).filter(
137
+ (dep) => !dep.startsWith('@shellui/'),
138
+ );
139
+ } catch (e) {
140
+ console.warn(`Warning: Failed to read @shellui/core dependencies: ${e.message}`);
141
+ return [];
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Get packages that should be excluded from optimization
147
+ * These are @shellui/* packages that should always load from source
148
+ * @returns {string[]} Array of package names to exclude
149
+ */
150
+ export function getShelluiExcludePackages() {
151
+ try {
152
+ const corePackagePath = resolvePackagePath('@shellui/core');
153
+ const packageJsonPath = path.join(corePackagePath, 'package.json');
154
+
155
+ if (!fs.existsSync(packageJsonPath)) {
156
+ return ['@shellui/core', '@shellui/sdk'];
157
+ }
158
+
159
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
160
+ const dependencies = packageJson.dependencies || {};
161
+
162
+ // Extract @shellui/* packages that should be excluded
163
+ const shelluiPackages = Object.keys(dependencies).filter(
164
+ (dep) => dep.startsWith('@shellui/'),
165
+ );
166
+
167
+ // Always include @shellui/core and @shellui/sdk
168
+ const exclude = ['@shellui/core', '@shellui/sdk'];
169
+ shelluiPackages.forEach((pkg) => {
170
+ if (!exclude.includes(pkg)) {
171
+ exclude.push(pkg);
172
+ }
173
+ });
174
+
175
+ return exclude;
176
+ } catch (e) {
177
+ console.warn(`Warning: Failed to read @shellui/* packages: ${e.message}`);
178
+ return ['@shellui/core', '@shellui/sdk'];
179
+ }
180
+ }
181
+
117
182
  /**
118
183
  * Create Vite optimizeDeps configuration to exclude @shellui/core from pre-bundling.
119
184
  * This prevents Vite from creating duplicate module instances during dependency optimization,
120
185
  * which is critical for React Context to work correctly in microfrontend iframe scenarios.
121
186
  *
187
+ * Dynamically reads dependencies from @shellui/core to ensure all new dependencies
188
+ * are automatically included in optimization.
189
+ *
122
190
  * Note: We do NOT exclude React/ReactDOM here because Vite needs to optimize them.
123
191
  * The resolve.dedupe configuration handles ensuring only one React instance is used.
124
192
  * @returns {Object} Vite optimizeDeps configuration
125
193
  */
126
194
  export function createViteOptimizeDepsConfig() {
195
+ const coreDependencies = getCoreDependencies();
196
+ const excludePackages = getShelluiExcludePackages();
197
+
127
198
  return {
128
- exclude: ['@shellui/core'],
199
+ exclude: excludePackages,
200
+ include: coreDependencies,
129
201
  };
130
202
  }
203
+
204
+ /**
205
+ * Get deduplication list for Vite resolve configuration
206
+ * Includes React, ReactDOM, @shellui packages, and all @shellui/core dependencies
207
+ * @returns {string[]} Array of package names to dedupe
208
+ */
209
+ export function getDedupeList() {
210
+ const coreDependencies = getCoreDependencies();
211
+ const shelluiPackages = getShelluiExcludePackages();
212
+
213
+ // Base dedupe list: React, ReactDOM, and @shellui packages
214
+ const dedupe = ['react', 'react-dom', ...shelluiPackages];
215
+
216
+ // Add all core dependencies to ensure they resolve from project root
217
+ coreDependencies.forEach((dep) => {
218
+ if (!dedupe.includes(dep)) {
219
+ dedupe.push(dep);
220
+ }
221
+ });
222
+
223
+ return dedupe;
224
+ }