From abaa7d2822d9f9e869fa8d51158a342dd0b1f729 Mon Sep 17 00:00:00 2001 From: Dan Ichim Date: Thu, 17 Sep 2026 16:45:28 +0300 Subject: [PATCH 1/3] jenkins pnpm --- config/webpack.config.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/config/webpack.config.js b/config/webpack.config.js index 54be65f8..c9b9c307 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -276,6 +276,32 @@ module.exports = function ( return Array.isArray(paths) ? paths : [paths]; }; + // When @enact/* is npm-linked from a pnpm workspace, nested deps (e.g. xhr's + // "global") live in the workspace node_modules, not beside the linked package. + // Keep resolve.symlinks=false for ilib, but search that store as well. + const getLinkedPnpmNodeModules = context => { + const pkgs = ['i18n', 'core', 'ui', 'spotlight', 'webos']; + for (let i = 0; i < pkgs.length; i++) { + try { + const linked = path.join(context, 'node_modules', '@enact', pkgs[i]); + if (!fs.existsSync(linked)) continue; + let dir = fs.realpathSync(linked); + for (let depth = 0; depth < 6; depth++) { + const nm = path.join(dir, 'node_modules'); + if (fs.existsSync(path.join(nm, '.pnpm'))) { + return [nm]; + } + const parent = path.dirname(dir); + if (parent === dir) break; + dir = parent; + } + } catch (e) { + // ignore missing or broken links + } + } + return []; + }; + return { mode: isEnvProduction ? 'production' : 'development', // Don't attempt to continue if there are any errors. @@ -354,6 +380,7 @@ module.exports = function ( modules: [ path.resolve('./node_modules'), 'node_modules', + ...getLinkedPnpmNodeModules(app.context), ...getAdditionalModulePaths(app.additionalModulePaths) ], // Don't resolve symlinks to their underlying paths From c788270c5e51475d0a796a79a67f043896a52074 Mon Sep 17 00:00:00 2001 From: Dan Ichim Date: Mon, 21 Sep 2026 14:05:16 +0300 Subject: [PATCH 2/3] Update config/webpack.config.js Co-authored-by: Daniel Stoian <63335068+daniel-stoian-lgp@users.noreply.github.com> --- config/webpack.config.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index c9b9c307..44bc646d 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -277,29 +277,33 @@ module.exports = function ( }; // When @enact/* is npm-linked from a pnpm workspace, nested deps (e.g. xhr's - // "global") live in the workspace node_modules, not beside the linked package. - // Keep resolve.symlinks=false for ilib, but search that store as well. + // "global") live in the workspace store rather than beside the linked package, + // and resolve.symlinks=false (needed for ilib) stops webpack from walking up + // into it. Resolve against pnpm's hoist directory, which holds the workspace's + // transitive deps -- deliberately not the workspace root, which would expose + // the framework's own devDependencies to the app if it were publicly hoisted. const getLinkedPnpmNodeModules = context => { - const pkgs = ['i18n', 'core', 'ui', 'spotlight', 'webos']; - for (let i = 0; i < pkgs.length; i++) { + const stores = []; + ['core', 'i18n', 'spotlight', 'ui', 'webos'].forEach(name => { try { - const linked = path.join(context, 'node_modules', '@enact', pkgs[i]); - if (!fs.existsSync(linked)) continue; + const linked = path.join(context, 'node_modules', '@enact', name); + if (!fs.existsSync(linked)) return; let dir = fs.realpathSync(linked); for (let depth = 0; depth < 6; depth++) { - const nm = path.join(dir, 'node_modules'); - if (fs.existsSync(path.join(nm, '.pnpm'))) { - return [nm]; + const hoisted = path.join(dir, 'node_modules', '.pnpm', 'node_modules'); + if (fs.existsSync(hoisted)) { + if (!stores.includes(hoisted)) stores.push(hoisted); + return; } const parent = path.dirname(dir); - if (parent === dir) break; + if (parent === dir) return; dir = parent; } } catch (e) { // ignore missing or broken links } - } - return []; + }); + return stores; }; return { From cc00a6d3ba75afe1cf2c5d8eaa5c6b058ea2f265 Mon Sep 17 00:00:00 2001 From: Dan Ichim Date: Mon, 21 Sep 2026 14:46:40 +0300 Subject: [PATCH 3/3] fix cli --- config/webpack.config.js | 52 +++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 44bc646d..9e28bcde 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -277,22 +277,58 @@ module.exports = function ( }; // When @enact/* is npm-linked from a pnpm workspace, nested deps (e.g. xhr's - // "global") live in the workspace store rather than beside the linked package, - // and resolve.symlinks=false (needed for ilib) stops webpack from walking up - // into it. Resolve against pnpm's hoist directory, which holds the workspace's - // transitive deps -- deliberately not the workspace root, which would expose - // the framework's own devDependencies to the app if it were publicly hoisted. + // "global") live beside the real package in the virtual store, not beside the + // symlink webpack sees with resolve.symlinks=false (needed for ilib). + // Follow those nested links into .pnpm//node_modules so siblings resolve. + // Also search pnpm's hoist dir and the workspace node_modules created by + // shamefullyHoist (the inner .pnpm/node_modules dir is not always present). const getLinkedPnpmNodeModules = context => { const stores = []; + const add = dir => { + if (dir && fs.existsSync(dir) && !stores.includes(dir)) stores.push(dir); + }; + const addRealParent = entry => { + try { + if (fs.existsSync(entry)) add(path.dirname(fs.realpathSync(entry))); + } catch (e) { + // ignore missing or broken links + } + }; + const addNestedStores = nodeModulesDir => { + let names; + try { + names = fs.readdirSync(nodeModulesDir); + } catch (e) { + return; + } + names.forEach(name => { + if (name.startsWith('.')) return; + const full = path.join(nodeModulesDir, name); + if (name.startsWith('@')) { + let scoped; + try { + scoped = fs.readdirSync(full); + } catch (err) { + return; + } + scoped.forEach(child => addRealParent(path.join(full, child))); + return; + } + addRealParent(full); + }); + }; + ['core', 'i18n', 'spotlight', 'ui', 'webos'].forEach(name => { try { const linked = path.join(context, 'node_modules', '@enact', name); if (!fs.existsSync(linked)) return; let dir = fs.realpathSync(linked); + addNestedStores(path.join(dir, 'node_modules')); for (let depth = 0; depth < 6; depth++) { - const hoisted = path.join(dir, 'node_modules', '.pnpm', 'node_modules'); - if (fs.existsSync(hoisted)) { - if (!stores.includes(hoisted)) stores.push(hoisted); + const pnpmDir = path.join(dir, 'node_modules', '.pnpm'); + if (fs.existsSync(pnpmDir)) { + add(path.join(pnpmDir, 'node_modules')); + add(path.join(dir, 'node_modules')); return; } const parent = path.dirname(dir);