7.0.0 - The ESM-Only & Async-first Release
Important
v7.0.0 is one of the largest releases in Encore's history, and honestly, we're excited about this one.
The project has been modernized top to bottom, inside and out.
What changed for you: Encore is now ESM-only, Encore.getWebpackConfig() is async, Babel 8 is required, and CSS minification is no longer enabled by default. These are real breaking changes, so please follow the upgrade steps below.
What changed under the hood: the codebase moved from CommonJS to ESM, the test suite from Mocha/Sinon/Chai to Vitest, the package manager from Yarn to PNPM, and code formatting to Oxfmt. Dependabot (grouped dependency updates) and Zizmor (GitHub Actions security audits) are now keeping CI in check too. It's a much healthier codebase going into this next chapter.
The Node.js ecosystem has largely moved to ESM as the standard module format. Most actively maintained packages now ship ESM-only, and since Encore already requires Node.js ^22.13.0 || >=24.0 (which has full ESM support), continuing to publish as CJS would mean fighting the ecosystem: pinning to older dependencies, adding workarounds, and missing out on tree-shaking and static analysis.
Moving to ESM also unlocks async/await in Encore's internals. Now that getWebpackConfig() is natively async, Encore can adopt modern async APIs from the ecosystem without hacks.
BC Breaks and upgrade steps
-
Migrate from CommonJS to ESM (by @Kocal in #1402): the package now requires
"type": "module"in your project or the use of.mjsfile extensions. Update yourwebpack.config.js:// Before (CJS) const Encore = require('@symfony/webpack-encore'); // ... module.exports = Encore.getWebpackConfig(); // After (ESM) import Encore from '@symfony/webpack-encore'; // ... export default await Encore.getWebpackConfig();
Note:
Encore.getWebpackConfig()is now async and returns aPromise. Useawaitat the
top level of your webpack config (webpack supports async config files natively). -
If you prefer not to add
"type": "module", rename your webpack config towebpack.config.mjsinstead; webpack detects the.mjsextension and treats it as ESM automatically. -
Replace
__dirnameand__filenamewith their ESM equivalents in your webpack config:// Before (CJS) path.resolve(__dirname, 'src/utilities/'); config: [__filename]; // After (ESM) path.resolve(import.meta.dirname, 'src/utilities/'); config: [import.meta.filename];
-
Replace
require()calls in your webpack config withimportstatements:// Before (CJS) const path = require('path'); // After (ESM) import path from 'path';
Similarly,
require.resolve()becomesimport.meta.resolve():// Before (CJS) options.implementation = require.resolve('sass-embedded'); // After (ESM) import { fileURLToPath } from 'url'; options.implementation = fileURLToPath(import.meta.resolve('sass-embedded'));
If you need to require a CJS-only package, use
createRequire:import { createRequire } from 'module'; const require = createRequire(import.meta.url); const somePackage = require('cjs-only-package');
-
If you use StimulusBundle, update the
require.context()call in yourassets/stimulus_bootstrap.jsfile (previouslyassets/bootstrap.js) to webpack's ESM-friendlyimport.meta.webpackContext(), sincerequire.context()is not available in ESM modules:// Before (CJS) export const app = startStimulusApp( require.context( '@symfony/stimulus-bridge/lazy-controller-loader!./controllers', true, /\.[jt]sx?$/ ) ); // After (ESM) export const app = startStimulusApp( import.meta.webpackContext( '@symfony/stimulus-bridge/lazy-controller-loader!./controllers', { recursive: true, regExp: /\.[jt]sx?$/, } ) );
-
Config files using CJS syntax (
module.exports,require()) must be renamed to.cjsif your project has"type": "module"in itspackage.json, for example:postcss.config.js->postcss.config.cjsbabel.config.js->babel.config.cjs
Or, preferably, rewrite them as ESM:
// postcss.config.js (ESM) import autoprefixer from 'autoprefixer'; export default { plugins: [autoprefixer()], };
-
With
"type": "module", webpack enablesresolve.fullySpecifiedby default, so file extensions are now required in some imports that previously worked without them:- Relative imports:
import('./my-dependency')->import('./my-dependency.js') - Deep package imports from packages without an
"exports"field, for example:import delegate from 'licia/delegate'->import delegate from 'licia/delegate.js'import 'jquery-ui/ui/widgets/progressbar'->import 'jquery-ui/ui/widgets/progressbar.js'
- Relative imports:
-
The package
"exports"field is now restrictive: only"@symfony/webpack-encore"and"@symfony/webpack-encore/lib/plugins/plugin-priorities.js"are exposed as public entry points.
Direct imports of other internal modules will no longer work. -
Drop support for Babel 7 and require Babel 8 (by @Kocal in #1439):
@babel/core,@babel/preset-env,@babel/preset-react,@babel/preset-typescript, and@babel/plugin-transform-react-jsxnow require^8.0.0. Upgrade your Babel dependencies and follow the migration guide. -
Raise the minimum Node.js version to
^22.18.0 || ^24.11.0 || >=26.0(required by Babel 8). -
Yarn Plug'n'Play users must upgrade to Yarn
>=4.6.0for proper resolution of ESM-only Babel 8
packages:yarn set version 4.6.0. -
The
useBuiltInsandcorejsoptions ofEncore.configureBabel()/Encore.configureBabelPresetEnv()are no longer supported: Babel 8 removed them from@babel/preset-env. Encore now throws an explicit error when they are set. To polyfill, usebabel-plugin-polyfill-corejs3viaEncore.configureBabel((babelConfig) => babelConfig.plugins.push(...))or an external Babel config. -
Without a
browserslistconfiguration, Babel 8's@babel/preset-envtargets modern browsers by default instead of compiling to ES5. Add abrowserslistconfiguration to your project to transpile for older browsers. -
The archived
css-minimizer-webpack-pluginandterser-webpack-pluginpackages have been replaced by the unifiedminimizer-webpack-plugin.
Minifier packages (lightningcss,cssnano,csso,clean-css,esbuild,@swc/*,uglify-js) are now optional peer dependencies, installed on demand. In particularcssnano, previously pulled in transitively bycss-minimizer-webpack-plugin, is no longer installed by default. -
Encore.configureTerserPlugin()has been removed. UseEncore.configureJsMinimizerPlugin()
instead (it takes the same callback). -
CSS minification is no longer enabled by default. Choose and configure a CSS minifier via
configureCssMinimizerPlugin(); otherwise CSS is not minified in production.
The JS minimizer (Terser, bundled insideminimizer-webpack-plugin) still works with no extra setup.The
MinimizerPluginclass is passed as the second argument of the callback, so you don't need to importminimizer-webpack-pluginyourself (it would not resolve under pnpm, being a transitive dependency of Encore):// Lightning CSS, fast Rust-based minifier (npm install --save-dev lightningcss) Encore.configureCssMinimizerPlugin((options, MinimizerPlugin) => { options.minify = MinimizerPlugin.lightningCssMinify; }); // cssnano, PostCSS-based, closest to previous default (npm install --save-dev cssnano postcss) Encore.configureCssMinimizerPlugin((options, MinimizerPlugin) => { options.minify = MinimizerPlugin.cssnanoMinify; });
Other supported CSS minimizers:
csso,clean-css,esbuild(esbuildMinifyCss),@swc/css(swcMinifyCss). See the minimizer-webpack-plugin documentation for all available options.
Features
-
Add new
configureJsMinimizerPlugin(callback)method to configure JS minimization options.
BothconfigureJsMinimizerPlugin()andconfigureCssMinimizerPlugin()are now backed byminimizer-webpack-pluginand support switching to alternative minimizers through theminifyoption.
Minifier packages are optional peer dependencies, so install the one you actually use, and a clear error is thrown at build time if a minifier's backing package is not installed.
As inconfigureCssMinimizerPlugin(), theMinimizerPluginclass is passed as the second argument of the callback, so you don't need to importminimizer-webpack-pluginyourself:// Switch JS minimizer to esbuild (npm install --save-dev esbuild) Encore.configureJsMinimizerPlugin((options, MinimizerPlugin) => { options.minify = MinimizerPlugin.esbuildMinify; });
Available JS minimizers:
terserMinify(default, bundled),uglifyJsMinify,swcMinify,esbuildMinify.
See the minimizer-webpack-plugin documentation for all available options. -
Update postcss-loader support from 8.1.0 to 8.1.1 for ESM compatibility
-
Update minimum version of webpack to
^5.82.0 -
Update minimum version of
@vue/compiler-sfcto^3.2.14, to matchvuepeer dependency requirement -
Add support for webpack-cli@7.0.0
-
Encore.copyFiles()now internally generates ESM exports for better webpack optimizations (scope hoisting, module concatenation) -
Add support for typescript@6.0.0 (by @stof in #1411)
-
The runtime version check for optional dependencies now reads supported version ranges from
peerDependenciesinstead ofdevDependencies(by @Kocal in #1426)
New Contributors
- @frykten made their first contribution in #1434
- @PhilDaiguille made their first contribution in #1436
Full Changelog: v6.0.0...v7.0.0