Skip to content

Remove the root node_modules symlink #91

Closed

Description

@loevgaard

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.js does not say so, so nobody reading the config can tell why the build works.
  • A symlink in git is fragile. On Windows without core.symlinks it 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_modules in .gitignore. With the trailing slash the pattern only matches a directory, so a symlink someone recreates would be committed again;
  • drop /node_modules from .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 into tests/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 under vendor/, and the same fallback would be needed. getWebpackConfig() returns a plain webpack config, so resolve.modules can 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 build in tests/Application works from a fresh clone.
  • Where resolve.modules is needed, webpack.config.js says why.

Activity

  1. loevgaard commented on Oct 19, 2026

    @loevgaard
    MemberAuthor

    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.x and 2.0.x: deleted, no longer maintained. Their last commits were 95a949fd0b168ca6ac2857db10fa2d188cef4c6a (1.12.x) and ec9dd41efab9619976ac9895d28f4da00f878f95 (2.0.x), in case a branch needs to be recreated.
  2. loevgaard commented on Oct 19, 2026

    @loevgaard
    MemberAuthor

    Done on all maintained branches: 2.2.x in #93 and 1.14.x in #96. On 1.14.x the webpack config now falls back to the test application's node_modules via resolve.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.x and 2.0.x have been deleted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions