Repository navigation
Description
Every maintained branch (1.14.x, 2.2.x) had a symlink at the repository root, node_modules -> tests/Application/node_modules, and every plugin generated from the skeleton copies it. It makes the asset build depend on something nothing in the build configuration mentions, so it should go.
Why it is there
Webpack resolves an import of a package (import 'semantic-ui-css') the way Node does: it walks up from the directory of the importing file and looks for a node_modules folder in each parent. In the 1.x test application the entries are Sylius' own files, ../../vendor/sylius/sylius/src/Sylius/Bundle/{Shop,Admin}Bundle/Resources/private/entry.js. Walking up from there passes vendor/ and the repository root, but never tests/Application/node_modules, where the packages are installed. The root symlink puts a node_modules on that path. Without it the build fails with errors like Module not found: ".../ShopBundle/Resources/private/entry.js" contains a reference to the file "semantic-ui-css/semantic.css". Sylius' own PluginSkeleton does the same.
Why remove it
- The build depends on it, but
webpack.config.jsdoes not say so, so nobody reading the config can tell why the build works. - A symlink in git is fragile. On Windows without
core.symlinksit is checked out as a text file containing the path, and the build fails with the errors above. - Tools that walk the repository follow it into
tests/Application/node_modules.
How (1.x branches)
Tell webpack where to look instead, in tests/Application/webpack.config.js, on both the shop and the admin config:
// The entries live in vendor/, outside this directory, so the packages they import are not found by walking up from
// them; they fall back to the test application's own node_modules
const nodeModules = ['node_modules', path.resolve(__dirname, 'node_modules')];
shopConfig.resolve.modules = nodeModules;
adminConfig.resolve.modules = nodeModules;The relative node_modules keeps the normal lookup, so packages still resolve their own nested dependencies. The absolute path is the fallback the symlink provided. Then:
- delete the symlink;
- change
/node_modules/to/node_modulesin.gitignore. With the trailing slash the pattern only matches a directory, so a symlink someone recreates would be committed again; - drop
/node_modulesfrom.gitattributes.
This was done in Setono/SyliusGiftCardPlugin#408. CI built the shop and admin assets from a checkout without the symlink with the same warnings as on 1.x (11 shop, 13 admin), the end-to-end suite passed against them, and the PR reports byte-identical output under public/build.
2.x branches
These need checking rather than the same change. The test application gets Sylius' assets through @sylius-ui/admin and @sylius-ui/shop as file: dependencies, and their getWebpackConfig() adds the entries relative to the package's own __dirname.
- Yarn 1 copies a
file:dependency intotests/Application/node_modules, so the entries already live under it, and the symlink may not be needed at all. - npm symlinks a
file:dependency. Node and webpack then resolve the entries to their real path undervendor/, and the same fallback would be needed.getWebpackConfig()returns a plain webpack config, soresolve.modulescan be set on both configs exactly as above.
The skeleton's CI does not build the assets, so this has to be checked by hand: in a fresh clone without the symlink (one that has no node_modules in a parent directory), run yarn install && yarn build in tests/Application, and the same with npm if npm is meant to be supported.
Done when
- The symlink is gone on the maintained branches.
yarn install && yarn buildintests/Applicationworks from a fresh clone.- Where
resolve.modulesis needed,webpack.config.jssays why.
Activity
loevgaard commentedon Oct 19, 2026
Status:
2.2.x: done in Remove the root node_modules symlink #93.1.14.x: still to do (the 1.x approach described above).1.12.xand2.0.x: deleted, no longer maintained. Their last commits were95a949fd0b168ca6ac2857db10fa2d188cef4c6a(1.12.x) andec9dd41efab9619976ac9895d28f4da00f878f95(2.0.x), in case a branch needs to be recreated.loevgaard commentedon Oct 19, 2026
Done on all maintained branches:
2.2.xin #93 and1.14.xin #96. On 1.14.x the webpack config now falls back to the test application'snode_modulesviaresolve.modules, with a comment explaining why. A fresh clone without the symlink builds byte-identical assets to the old build with the symlink.1.12.xand2.0.xhave been deleted.