hshn/npm-bundle
Integrates npm package management into Symfony projects by exposing npm commands and configuration through the framework, letting PHP developers install, update, and manage JavaScript dependencies without leaving their existing Symfony workflow.
hshn/npm-bundle is a small Symfony bundle from the Symfony 2.x/3.x era that wraps two jobs: declaring npm package versions in Symfony config instead of a package.json, and shelling out to a package manager for installs and scripts. As of v0.3.0 (the first release since 2017-08-31, and the first new feature in the project's history — PR #2, "feature switching package manager (yarn)"), it can drive either npm or Yarn. Treat the new tag as a usability improvement, not as a sign of revived maintenance: still ~4 stars, still no dependents, still no Symfony 4+/6 support guarantees.
Minimal steps:
composer require hshn/npm-bundle:^0.3
app/AppKernel.php:
$bundles[] = new Hshn\NpmBundle\HshnNpmBundle();
Symfony 4+ in config/bundles.php. The bundle predates Flex recipes — you wire config by hand.bin/console config:dump-reference hshn_npm
bin/console list hshn # confirm the command names it actually registers
Look specifically for the package-manager switch (the v0.3.0 feature — likely a key such as package_manager: yarn or manager: yarn; confirm the exact name and allowed values from the dump).hshn_npm:
binary: /usr/bin/npm # or: /usr/local/bin/yarn
package_manager: yarn # v0.3.0+; verify the real key name
packages:
jquery: "3.2.1"
Where to look first, in order: the README, DependencyInjection/Configuration.php (the real API surface, and the place the new package-manager option is defined), Command/ (what you can actually run), and Resources/config/ (service IDs to override — the new switch is likely a service alias or a constructor argument you can also override).
First use case: you have one or two small front-end dependencies (jQuery, a datepicker) and no build pipeline, and you want composer install-style declarative version pinning plus a console command your deploy script can call. The v0.3.0 Yarn option matters here only if your team already standardised on Yarn; otherwise the npm path is unchanged.
Pick one package manager and enforce it in config. v0.3.0 lets you switch to Yarn, but nothing in the bundle stops a developer from running npm install by hand in the same directory and producing a package-lock.json next to a yarn.lock. Choose one, set it in hshn_npm config, commit only that lockfile, and add the other manager's lockfile to .gitignore.
Declarative packages vs. a real manifest. The config-as-manifest approach only works for flat dependency lists. The moment you need transitive pinning, devDependencies, resolutions, or Yarn workspaces, write a package.json and use the bundle purely for the "run the package manager in the right directory" part — or drop it. This is now slightly less painful with Yarn's resolutions, but the bundle still only expresses a flat map of name → version.
Deploy hook pattern. The most durable use is calling the bundle's install command from your release step, after composer install and before cache warmup:
# Deployer / Capistrano style
bin/console hshn:npm:install --env=prod
bin/console assets:install --symlink
bin/console assetic:dump --env=prod
Keep node_modules out of your release artifact only if your target hosts have the chosen package manager; otherwise install in CI and ship the built assets.
Asset exposure. Symfony's asset() does not resolve node_modules/ paths. Two patterns work:
node_modules/jquery/dist/jquery.min.js into web/vendor/, then {{ asset('vendor/jquery.min.js') }} from Twig. This is the pattern that survives a migration off the bundle.bin/console debug:twig / debug:container --tag=assetic.loader. Confirm before relying on it.Environment split. Install full dependencies in dev and a pruned set for prod. The flag differs per manager, so express it in the manager's own vocabulary:
{
"scripts": {
"prod:npm": "npm install --production && npm run build",
"prod:yarn": "yarn install --production && yarn run build"
}
}
If you switch managers, audit every place you hardcoded npm — deploy scripts, CI, Dockerfiles, docs — not just the bundle config.
Integration with Assetic (period-appropriate). If you're on this bundle, you're likely also on Assetic. Let npm/Yarn own compilation (Less/Sass/Babel) and let Assetic own concatenation and cache-busting — don't have both try to process the same source files.
CI. Run the install in CI, cache the manager's global cache (~/.npm or ~/.cache/yarn) plus node_modules keyed on the lockfile, and fail the build on lockfile mismatch (npm ci, yarn install --frozen-lockfile). This is the single highest-value improvement you can make to an inherited install of this bundle.
composer audit won't help you — the risk is drift, not CVEs.node_modules at all and will break every path assumption in the bundle.www-data or under PHP-FPM. Set binary explicitly (that is what the option is for) and run installs as the deploy user, never at request time. With Yarn, remember Corepack may need corepack enable before yarn exists on PATH.--production (Classic Yarn / old npm), --omit=dev (npm 8+), --no-audit (npm only). The bundle passes arguments through, so any flag you inject via a decorated exec service must match the configured manager.postinstall scripts. Install is a deploy-time concern only.assets:install --symlink plus node_modules symlinks is a reliable way to break Windows dev machines and some Docker volume mounts. Prefer copying for vendor assets.bin/console <cmd> -vvv to see the exact process invocation, and debug:container hshn_npm to find the service doing the exec — and, post-v0.3.0, to confirm which manager it actually resolved.config/services.yml (or app/config/services.yml on old Symfony) rather than editing vendor code. After v0.3.0, also check whether the manager switch is a service alias: rebinding it is cleaner than string-switching config, and a compiler pass or a decorated exec service remains the clean way to inject flags like --no-audit or --frozen-lockfile.How can I help you explore Laravel packages today?