Files
SimfonyBasics/spa/node_modules/@symfony/webpack-encore/index.js
2024-07-05 13:46:23 +02:00

1750 lines
51 KiB
JavaScript

/*
* This file is part of the Symfony Webpack Encore package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
'use strict';
const webpack = require('webpack'); // eslint-disable-line no-unused-vars
const EncoreProxy = require('./lib/EncoreProxy');
const WebpackConfig = require('./lib/WebpackConfig');
const configGenerator = require('./lib/config-generator');
const validator = require('./lib/config/validator');
const parseRuntime = require('./lib/config/parse-runtime');
const context = require('./lib/context');
let runtimeConfig = context.runtimeConfig;
let webpackConfig = runtimeConfig ? new WebpackConfig(runtimeConfig, true) : null;
class Encore {
/**
* The directory where your files should be output.
*
* If relative (e.g. web/build), it will be set relative
* to the directory where your package.json lives.
*
* @param {string} outputPath
* @returns {Encore}
*/
setOutputPath(outputPath) {
webpackConfig.setOutputPath(outputPath);
return this;
}
/**
* The public version of outputPath: the public path to outputPath.
*
* For example, if "web" is your document root, then:
*
* ```
* Encore
* .setOutputPath('web/build')
* .setPublicPath('/build')
* ```
*
* This can also be set to an absolute URL if you're using
* a CDN: publicPath is used as the prefix to all asset paths
* in the manifest.json file and internally in webpack:
*
* ```
* Encore
* .setOutputPath('web/build')
* .setPublicPath('https://coolcdn.com')
* // needed when public path is absolute
* .setManifestKeyPrefix('/build')
* ```
*
* @param {string} publicPath
* @returns {Encore}
*/
setPublicPath(publicPath) {
webpackConfig.setPublicPath(publicPath);
return this;
}
/**
* Used as a prefix to the *keys* in manifest.json. Not usually needed.
*
* You don't normally need to set this. When you *do* need to set
* it, an error will notify you.
*
* Typically, publicPath is used in the keys inside manifest.json.
* But if publicPath is absolute, then we require you to set this.
* For example:
*
* ```
* Encore
* .setOutputPath('web/build')
* .setPublicPath('https://coolcdn.com/FOO')
* .setManifestKeyPrefix('build/')
* ```
*
* The manifest.json file would look something like this:
*
* ```
* {
* "build/main.js": "https://coolcdn.com/FOO/main.a54f3ccd2.js"
* }
* ```
*
* @param {string} manifestKeyPrefix
* @returns {Encore}
*/
setManifestKeyPrefix(manifestKeyPrefix) {
webpackConfig.setManifestKeyPrefix(manifestKeyPrefix);
return this;
}
/**
* Allows you to configure the options passed to the DefinePlugin.
* A list of available options can be found at https://webpack.js.org/plugins/define-plugin/
*
* For example:
*
* ```
* Encore.configureDefinePlugin((options) => {
* options.VERSION = JSON.stringify('1.0.0');
* })
* ```
*
* @param {function} definePluginOptionsCallback
* @returns {Encore}
*/
configureDefinePlugin(definePluginOptionsCallback = () => {}) {
webpackConfig.configureDefinePlugin(definePluginOptionsCallback);
return this;
}
/**
* Allows you to configure the options passed to the @nuxt/friendly-errors-webpack-plugin.
* A list of available options can be found at https://github.com/nuxt/friendly-errors-webpack-plugin
*
* For example:
*
* ```
* Encore.configureFriendlyErrorsPlugin((options) => {
* options.clearConsole = true;
* })
* ```
*
* @param {function} friendlyErrorsPluginOptionsCallback
* @returns {Encore}
*/
configureFriendlyErrorsPlugin(friendlyErrorsPluginOptionsCallback = () => {}) {
webpackConfig.configureFriendlyErrorsPlugin(friendlyErrorsPluginOptionsCallback);
return this;
}
/**
* Allows you to configure the options passed to webpack-manifest-plugin.
* A list of available options can be found at https://github.com/danethurber/webpack-manifest-plugin
*
* For example:
*
* ```
* Encore.configureManifestPlugin((options) => {
* options.fileName = '../../var/assets/manifest.json';
* })
* ```
*
* @param {function} manifestPluginOptionsCallback
* @returns {Encore}
*/
configureManifestPlugin(manifestPluginOptionsCallback = () => {}) {
webpackConfig.configureManifestPlugin(manifestPluginOptionsCallback);
return this;
}
/**
* Allows you to configure the options passed to the terser-webpack-plugin.
* A list of available options can be found at https://github.com/webpack-contrib/terser-webpack-plugin
*
* For example:
*
* ```
* Encore.configureTerserPlugin((options) => {
* options.cache = true;
* options.terserOptions = {
* output: {
* comments: false
* }
* }
* })
* ```
*
* @param {function} terserPluginOptionsCallback
* @returns {Encore}
*/
configureTerserPlugin(terserPluginOptionsCallback = () => {}) {
webpackConfig.configureTerserPlugin(terserPluginOptionsCallback);
return this;
}
/**
* Allows you to configure the options passed to the css-minimizer-webpack-plugin.
* A list of available options can be found at https://github.com/webpack-contrib/css-minimizer-webpack-plugin
*
* For example:
*
* ```
* Encore.configureCssMinimizerPlugin((options) => {
* options.parallel = false;
* })
* ```
*
* @param {function} cssMinimizerPluginOptionsCallback
* @returns {Encore}
*/
configureCssMinimizerPlugin(cssMinimizerPluginOptionsCallback = () => {}) {
webpackConfig.configureCssMinimizerPlugin(cssMinimizerPluginOptionsCallback);
return this;
}
/**
* Adds a JavaScript file that should be webpacked:
*
* ```
* // final output file will be main.js in the output directory
* Encore.addEntry('main', './path/to/some_file.js');
* ```
*
* If the JavaScript file imports/requires CSS/Sass/LESS files,
* then a CSS file (e.g. main.css) will also be output.
*
* @param {string} name The name (without extension) that will be used
* as the output filename (e.g. app will become app.js)
* in the output directory.
* @param {string|Array} src The path to the source file (or files)
* @returns {Encore}
*/
addEntry(name, src) {
webpackConfig.addEntry(name, src);
return this;
}
/**
* Adds a collection of JavaScript files that should be webpacked:
*
* ```
* // final output file will be main.js in the output directory
* Encore.addEntries({
* main: './path/to/some_file.js',
* secondary: './path/to/another_file.js',
* });
* ```
*
* If the JavaScript files imports/requires CSS/Sass/LESS files,
* then a CSS file (e.g. main.css) will also be output.
*
* @param {Object.<string, string|array>} entries where the Keys are the
* names (without extension) that will be used
* as the output filename (e.g. app will become app.js)
* in the output directory. The values are the path(s)
* to the source file(s).
* @returns {Encore}
*/
addEntries(entries) {
webpackConfig.addEntries(entries);
return this;
}
/**
* Adds a CSS/SASS/LESS file that should be webpacked:
*
* ```
* // final output file will be main.css in the output directory
* Encore.addStyleEntry('main', './path/to/some_file.css');
* ```
*
* This is actually not something Webpack does natively, and you
* should avoid using this function when possible. A better option
* is to use addEntry() and then require/import your CSS files from
* within your JavaScript files.
*
* @param {string} name The name (without extension) that will be used
* as the output filename (e.g. app will become app.css)
* in the output directory.
* @param {string|Array} src The path to the source file (or files)
* @returns {Encore}
*/
addStyleEntry(name, src) {
webpackConfig.addStyleEntry(name, src);
return this;
}
/**
* Add a plugin to the sets of plugins already registered by Encore
*
* For example, if you want to add the "webpack.IgnorePlugin()", then:
*
* ```
* Encore.addPlugin(new webpack.IgnorePlugin(requestRegExp, contextRegExp))
* ```
*
* By default custom plugins are added after the ones managed by Encore
* but you can also set a priority to define where your plugin will be
* added in the generated Webpack config.
*
* For example, if a plugin has a priority of 0 and you want to add
* another plugin after it, then:
*
* ```
* Encore.addPlugin(new MyWebpackPlugin(), -10)
* ```
*
* The priority of each plugin added by Encore can be found in the
* "lib/plugins/plugin-priorities.js" file. It is recommended to use
* these constants if you want to add a plugin using the same priority
* as one managed by Encore in order to avoid backward compatibility
* breaks.
*
* For example, if you want one of your plugins to have the same priority
* than the DefinePlugin:
*
* ```
* const Encore = require('@symfony/webpack-encore');
* const PluginPriorities = require('@symfony/webpack-encore/lib/plugins/plugin-priorities.js');
*
* Encore.addPlugin(new MyWebpackPlugin(), PluginPriorities.DefinePlugin);
* ```
*
* @param {object} plugin
* @param {number} priority
* @returns {Encore}
*/
addPlugin(plugin, priority = 0) {
webpackConfig.addPlugin(plugin, priority);
return this;
}
/**
* Adds a custom loader config
*
* @param {object} loader The loader config object
*
* @returns {Encore}
*/
addLoader(loader) {
webpackConfig.addLoader(loader);
return this;
}
/**
* Alias to addLoader
*
* @param {object} rule
*
* @returns {Encore}
*/
addRule(rule) {
this.addLoader(rule);
return this;
}
/**
* Allow you to add aliases that will be used by
* Webpack when trying to resolve modules.
*
* See https://webpack.js.org/configuration/resolve/#resolve-alias
*
* For example:
*
* ```
* Encore.addAliases({
* Utilities: path.resolve(__dirname, 'src/utilities/'),
* Templates: path.resolve(__dirname, 'src/templates/')
* })
* ```
*
* @param {object} aliases
*
* @returns {Encore}
*/
addAliases(aliases) {
webpackConfig.addAliases(aliases);
return this;
}
/**
* Allow you to exclude some dependencies from the output bundles.
*
* See https://webpack.js.org/configuration/externals/
*
* For example:
*
* ```
* Encore.addExternals({
* jquery: 'jQuery',
* react: 'react'
* });
* ```
*
* Or:
*
* ```
* const nodeExternals = require('webpack-node-externals');
*
* Encore.addExternals(
* nodeExternals()
* );
*
* // or add multiple things at once
* Encore.addExternals([
* nodeExternals(),
* /^(jquery|\$)$/i
* ]);
* ```
*
* @param {*} externals
*
* @returns {Encore}
*/
addExternals(externals) {
webpackConfig.addExternals(externals);
return this;
}
/**
* When enabled, files are rendered with a hash based
* on their contents (e.g. main.a2b61cc.js)
*
* A manifest.json file will be rendered to the output
* directory with a map from the original file path to
* the versioned path (e.g. `builds/main.js` => `builds/main.a2b61cc.js`)
*
* Note that the versioning must be disabled if you
* want to use the dev-server.
*
* For example:
*
* ```
* Encore.enableVersioning(Encore.isProduction());
* ```
*
* @param {boolean} enabled
* @returns {Encore}
*/
enableVersioning(enabled = true) {
webpackConfig.enableVersioning(enabled);
return this;
}
/**
* When enabled, all final CSS and JS files will be rendered
* with sourcemaps to help debugging.
*
* The *type* of source map will differ between a development
* or production build.
*
* For example if you want to always generate sourcemaps:
*
* ```
* Encore.enableSourceMaps();
* ```
*
* Or only enable them when not in production mode:
*
* ```
* Encore.enableSourceMaps(!Encore.isProduction());
* ```
*
* @param {boolean} enabled
* @returns {Encore}
*/
enableSourceMaps(enabled = true) {
webpackConfig.enableSourceMaps(enabled);
return this;
}
/**
* Add a new cache group to Webpack's SplitChunksPlugin.
* This can, for instance, be used to extract code that
* is common to multiple entries into its own chunk.
*
* See: https://webpack.js.org/plugins/split-chunks-plugin/#examples
*
* For example:
*
* ```
* Encore.addCacheGroup('vendor', {
* test: /[\\/]node_modules[\\/]react/
* });
* ```
*
* You can pass all the options supported by the SplitChunksPlugin
* but also the following shorthand provided by Encore:
*
* * `node_modules`: An array of `node_modules` packages names
*
* For example:
*
* ```
* Encore.addCacheGroup('vendor', {
* node_modules: ['react', 'react-dom']
* });
* ```
*
* At least one of the `test` or the `node_modules` option
* should be provided.
*
* By default, the new cache group will be created with the
* following options:
* * `chunks` set to `"all"`
* * `enforce` set to `true`
* * `name` set to the value of the "name" parameter
*
* @param {string} name The chunk name (e.g. vendor to create a vendor.js)
* @param {object} options Cache group option
* @returns {Encore}
*/
addCacheGroup(name, options) {
webpackConfig.addCacheGroup(name, options);
return this;
}
/**
* Copy files or folders to the build directory.
*
* For example:
*
* ```
* // Copy the content of a whole directory and its subdirectories
* Encore.copyFiles({ from: './assets/images' });
*
* // Only copy files matching a given pattern
* Encore.copyFiles({ from: './assets/images', pattern: /\.(png|jpg|jpeg)$/ })
*
* // Set the path the files are copied to
* Encore.copyFiles({
* from: './assets/images',
* pattern: /\.(png|jpg|jpeg)$/,
* // to path is relative to the build directory
* to: 'images/[path][name].[ext]'
* })
*
* // Version files
* Encore.copyFiles({
* from: './assets/images',
* to: 'images/[path][name].[hash:8].[ext]'
* })
*
* // Add multiple configs in a single call
* Encore.copyFiles([
* { from: './assets/images' },
* { from: './txt', pattern: /\.txt$/ },
* ]);
*
* // Set the context path: files will be copied
* // into an images/ directory in the output dir
* Encore.copyFiles({
* from: './assets/images',
* to: '[path][name].[hash:8].[ext]',
* context: './assets'
* });
* ```
*
* Notes:
* * No transformation is applied to the copied files (for instance
* copying a CSS file won't minify it)
*
* Supported options:
* * {string} from (mandatory)
* The path of the source directory (mandatory)
* * {RegExp|string} pattern (default: all files)
* A regular expression (or a string containing one) that
* the filenames must match in order to be copied
* * {string} to (default: [path][name].[ext])
* Where the files must be copied to. You can add all the
* placeholders supported by the file-loader.
* https://github.com/webpack-contrib/file-loader#placeholders
* * {boolean} includeSubdirectories (default: true)
* Whether or not the copy should include subdirectories.
* * {string} context (default: path of the source directory)
* The context to use as a root path when copying files.
*
* @param {object|Array} configs
* @returns {Encore}
*/
copyFiles(configs) {
webpackConfig.copyFiles(configs);
return this;
}
/**
* Tell Webpack to output a separate runtime.js file.
*
* This file must be included via a script tag before all
* other JavaScript files output by Encore.
*
* The runtime.js file is useful when you plan to include
* multiple entry files on the same page (e.g. a layout.js entry
* and a page-specific entry). If you are *not* including
* multiple entries on the same page, you can safely disable
* this - disableSingleRuntimeChunk() - and remove the extra script tags.
*
* If you *do* include multiple entry files on the same page,
* disabling the runtime.js file has two important consequences:
* A) Each entry file will contain the Webpack runtime, which
* means each contains some code that is duplicated in the other.
* B) If two entry files require the same module (e.g. jquery),
* they will receive *different* objects - not the *same* object.
* This can cause some confusion if you expect a "layout.js" entry
* to be able to "initialize" some jQuery plugins, because the
* jQuery required by the other entry will be a different instance,
* and so won't have the plugins initialized on it.
*
* @returns {Encore}
*/
enableSingleRuntimeChunk() {
webpackConfig.enableSingleRuntimeChunk();
return this;
}
/**
* Tell Webpack to *not* output a separate runtime.js file.
*
* See enableSingleRuntimeChunk() for more details.
*
* @returns {Encore}
*/
disableSingleRuntimeChunk() {
webpackConfig.disableSingleRuntimeChunk();
return this;
}
/**
* Tell Webpack to "split" your entry chunks.
*
* This will mean that, instead of adding 1 script tag
* to your page, your server-side code will need to read
* the entrypoints.json file in the build directory to
* determine the *multiple* .js (and .css) files that
* should be included for each entry.
*
* This is a performance optimization, but requires extra
* work (described above) to support this.
*
* @returns {Encore}
*/
splitEntryChunks() {
webpackConfig.splitEntryChunks();
return this;
}
/**
* Configure the optimization.splitChunks configuration.
*
* https://webpack.js.org/plugins/split-chunks-plugin/
*
* ```
* Encore.configureSplitChunks(function(splitChunks) {
* // change the configuration
* splitChunks.minSize = 0;
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
configureSplitChunks(callback) {
webpackConfig.configureSplitChunks(callback);
return this;
}
/**
* Configure the watchOptions and devServer.watchOptions configuration.
*
* https://webpack.js.org/configuration/watch/
* https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
*
* ```
* Encore.configureWatchOptions(function(watchOptions) {
* // change the configuration
* watchOptions.poll = 250; // useful when running inside a Virtual Machine
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
configureWatchOptions(callback) {
webpackConfig.configureWatchOptions(callback);
return this;
}
/**
* Configure the devServer configuration.
*
* https://webpack.js.org/configuration/dev-server
*
* ```
* Encore.configureDevServerOptions(function(options) {
* // change the configuration
* options.server = {
* type: 'https',
* options: {
* key: '<your SSL cert key content or path>',
* cert: '<your SSL cert content or path>',
* }
* };
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
configureDevServerOptions(callback) {
webpackConfig.configureDevServerOptions(callback);
return this;
}
/**
* Automatically make some variables available everywhere!
*
* Usage:
*
* ```
* WebpackConfig.autoProvideVariables({
* $: 'jquery',
* jQuery: 'jquery'
* });
* ```
*
* Then, whenever $ or jQuery are found in any
* modules, webpack will automatically require
* the "jquery" module so that the variable is available.
*
* This is useful for older packages, that might
* expect jQuery (or something else) to be a global variable.
*
* @param {object} variables
* @returns {Encore}
*/
autoProvideVariables(variables) {
webpackConfig.autoProvideVariables(variables);
return this;
}
/**
* Makes jQuery available everywhere. Equivalent to
*
* ```
* WebpackConfig.autoProvideVariables({
* $: 'jquery',
* jQuery: 'jquery',
* 'window.jQuery': 'jquery'
* });
* ```
*
* @returns {Encore}
*/
autoProvidejQuery() {
webpackConfig.autoProvidejQuery();
return this;
}
/**
* Enables the postcss-loader
*
* Once enabled, you must have a postcss.config.js config file.
*
* https://github.com/postcss/postcss-loader
*
* ```
* Encore.enablePostCssLoader();
* ```
*
* Or pass options to the loader
*
* ```
* Encore.enablePostCssLoader(function(options) {
* // https://github.com/postcss/postcss-loader#options
* // options.config = {...}
* })
* ```
*
* @param {function} postCssLoaderOptionsCallback
* @returns {Encore}
*/
enablePostCssLoader(postCssLoaderOptionsCallback = () => {}) {
webpackConfig.enablePostCssLoader(postCssLoaderOptionsCallback);
return this;
}
/**
* Call this if you plan on loading SASS files.
*
* ```
* Encore.enableSassLoader();
* ```
*
* Or pass options to node-sass
*
* ```
* Encore.enableSassLoader(function(options) {
* // https://github.com/sass/node-sass#options
* // options.includePaths = [...]
* }, {
* // set optional Encore-specific options
* // resolveUrlLoader: true
* });
* ```
*
* Supported options:
* * {boolean} resolveUrlLoader (default=true)
* Whether or not to use the resolve-url-loader.
* Setting to false can increase performance in some
* cases, especially when using bootstrap_sass. But,
* when disabled, all url()'s are resolved relative
* to the original entry file... not whatever file
* the url() appears in.
* * {object} resolveUrlLoaderOptions (default={})
* Options parameters for resolve-url-loader
* // https://www.npmjs.com/package/resolve-url-loader#options
*
* @param {function} sassLoaderOptionsCallback
* @param {object} encoreOptions
* @returns {Encore}
*/
enableSassLoader(sassLoaderOptionsCallback = () => {}, encoreOptions = {}) {
webpackConfig.enableSassLoader(sassLoaderOptionsCallback, encoreOptions);
return this;
}
/**
* Call this if you plan on loading less files.
*
* ```
* Encore.enableLessLoader();
* ```
*
* Or pass options to the loader
*
* ```
* Encore.enableLessLoader(function(options) {
* // https://github.com/webpack-contrib/less-loader#examples
* // http://lesscss.org/usage/#command-line-usage-options
* // options.relativeUrls = false;
* });
* ```
*
* @param {function} lessLoaderOptionsCallback
* @returns {Encore}
*/
enableLessLoader(lessLoaderOptionsCallback = () => {}) {
webpackConfig.enableLessLoader(lessLoaderOptionsCallback);
return this;
}
/**
* Call this if you plan on loading stylus files.
*
* ```
* Encore.enableStylusLoader();
* ```
*
* Or pass options to the loader
*
* ```
* Encore.enableStylusLoader(function(options) {
* // https://github.com/shama/stylus-loader
* // options.import = ['~library/index.styl'];
* });
* ```
*
* @param {function} stylusLoaderOptionsCallback
* @returns {Encore}
*/
enableStylusLoader(stylusLoaderOptionsCallback = () => {}) {
webpackConfig.enableStylusLoader(stylusLoaderOptionsCallback);
return this;
}
/**
* Configure babel, without needing a .babelrc file.
*
* https://babeljs.io/docs/usage/babelrc/
*
* ```
* Encore.configureBabel(function(babelConfig) {
* // change the babelConfig
* // if you use an external Babel configuration
* // this callback will NOT be used. In this case
* // you can pass null as the first parameter to
* // still be able to use some of the options below
* // without a warning.
* }, {
* // set optional Encore-specific options, for instance:
*
* // change the rule that determines which files
* // won't be processed by Babel
* exclude: /bower_components/
*
* // ...or keep the default rule but only allow
* // *some* Node modules to be processed by Babel
* includeNodeModules: ['foundation-sites']
*
* // automatically import polyfills where they
* // are needed
* useBuiltIns: 'usage'
*
* // if you set useBuiltIns you also have to add
* // core-js to your project using Yarn or npm and
* // inform Babel of the version it will use.
* corejs: 3
* });
* ```
*
* Supported options:
* * {Condition} exclude (default=/(node_modules|bower_components)/)
* A Webpack Condition passed to the JS/JSX rule that
* determines which files and folders should not be
* processed by Babel (https://webpack.js.org/configuration/module/#condition).
* Can be used even if you have an external Babel configuration
* (a babel.config.json file for instance)
* Warning: .babelrc config files don't apply to node_modules. Use
* babel.config.json instead to apply the same config to modules if
* they are not excluded anymore.
* Cannot be used if the "includeNodeModules" option is
* also set.
* * {string[]} includeNodeModules
* If set that option will include the given Node modules to
* the files that are processed by Babel.
* Can be used even if you have an external Babel configuration
* (a babel.config.json file for instance).
* Warning: .babelrc config files don't apply to node_modules. Use
* babel.config.json instead to apply the same config to these modules.
* Cannot be used if the "exclude" option is also set
* * {'usage'|'entry'|false} useBuiltIns (default=false)
* Set the "useBuiltIns" option of @babel/preset-env that changes
* how it handles polyfills (https://babeljs.io/docs/en/babel-preset-env#usebuiltins)
* Using it with 'entry' will require you to import core-js
* once in your whole app and will result in that import being replaced
* by individual polyfills. Using it with 'usage' will try to
* automatically detect which polyfills are needed for each file and
* add them accordingly.
* Cannot be used if you have an external Babel configuration (a .babelrc
* file for instance). In this case you can set the option directly into
* that configuration file.
* * {number|string|object} corejs (default=not set)
* Set the "corejs" option of @babel/preset-env.
* It should contain the version of core-js you added to your project
* if useBuiltIns isn't set to false.
*
* @param {function|null} callback
* @param {object} encoreOptions
* @returns {Encore}
*/
configureBabel(callback, encoreOptions = {}) {
webpackConfig.configureBabel(callback, encoreOptions);
return this;
}
/**
* Configure @babel/preset-env
*
* https://babeljs.io/docs/en/babel-preset-env
*
* ```
* Encore.configureBabelPresetEnv(function(options) {
* // change the @babel/preset-env config
* // if you use an external Babel configuration
* // this callback will NOT be used
* // options.corejs = 3;
* // options.useBuiltIns = 'usage';
* // ...
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
configureBabelPresetEnv(callback) {
webpackConfig.configureBabelPresetEnv(callback);
return this;
}
/**
* Configure the css-loader.
*
* https://github.com/webpack-contrib/css-loader#options
*
* ```
* Encore.configureCssLoader(function(config) {
* // change the config
* // config.minimize = true;
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
configureCssLoader(callback) {
webpackConfig.configureCssLoader(callback);
return this;
}
/**
* If enabled, the Stimulus bridge is used to load Stimulus controllers from PHP packages.
*
* @param {string} controllerJsonPath Path to the controllers.json file.
* @returns {Encore}
*/
enableStimulusBridge(controllerJsonPath) {
webpackConfig.enableStimulusBridge(controllerJsonPath);
return this;
}
/**
* Enables & configures persistent build caching.
*
* https://webpack.js.org/blog/2020-10-10-webpack-5-release/#persistent-caching
*
* ```
* Encore.enableBuildCache({
* // object of "buildDependencies"
* // https://webpack.js.org/configuration/other-options/#cachebuilddependencies
* // __filename means that changes to webpack.config.js should invalidate the cache
* config: [__filename],
* });
**
* // also configure other options the Webpack "cache" key
* Encore.enableBuildCache({ config: [__filename] }, (cache) => {
* cache.version: `${process.env.GIT_REV}`;
*
* cache.name: `${env.target}`
* });
* ```
*
* @param {object} buildDependencies
* @param {function} cacheCallback
* @returns {Encore}
*/
enableBuildCache(buildDependencies, cacheCallback = (cache) => {}) {
webpackConfig.enableBuildCache(buildDependencies, cacheCallback);
return this;
}
/**
* Configure the mini-css-extract-plugin.
*
* https://github.com/webpack-contrib/mini-css-extract-plugin#configuration
*
* ```
* Encore.configureMiniCssExtractPlugin(
* function(loaderConfig) {
* // change the loader's config
* // loaderConfig.reloadAll = true;
* },
* function(pluginConfig) {
* // change the plugin's config
* // pluginConfig.chunkFilename = '[id].css';
* }
* );
* ```
*
* @param {function} loaderOptionsCallback
* @param {function} pluginOptionsCallback
* @returns {Encore}
*/
configureMiniCssExtractPlugin(loaderOptionsCallback, pluginOptionsCallback = () => {}) {
webpackConfig.configureMiniCssExtractPlugin(loaderOptionsCallback, pluginOptionsCallback);
return this;
}
/**
* If enabled, the react preset is added to Babel.
*
* https://babeljs.io/docs/plugins/preset-react/
*
* @returns {Encore}
*/
enableReactPreset() {
webpackConfig.enableReactPreset();
return this;
}
/**
* If enabled, a Preact preset will be applied to
* the generated Webpack and Babel configuration.
*
* ```
* Encore.enablePreactPreset()
* ```
*
* If you wish to also use preact-compat (https://github.com/developit/preact-compat)
* you can enable it by setting the "preactCompat" option to true:
*
* ```
* Encore.enablePreactPreset({ preactCompat: true })
* ```
*
* @param {object} options
* @returns {Encore}
*/
enablePreactPreset(options = {}) {
webpackConfig.enablePreactPreset(options);
return this;
}
/**
* Call this to process TypeScript files through ts-loader.
*
* ```
* Encore.enableTypeScriptLoader()
* ```
*
* Or see Encore.enableBabelTypeScriptPreset() for a faster
* method of processing TypeScript files.
*
* Or, configure the ts-loader options:
*
* ```
* Encore.enableTypeScriptLoader(function(tsConfig) {
* // https://github.com/TypeStrong/ts-loader/blob/master/README.md#loader-options
* // tsConfig.silent = false;
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
enableTypeScriptLoader(callback = () => {}) {
webpackConfig.enableTypeScriptLoader(callback);
return this;
}
/**
* Call this to enable forked type checking for TypeScript loader
* https://github.com/TypeStrong/ts-loader/blob/v2.3.0/README.md#faster-builds
*
* This is a build optimization API to reduce build times.
*
* @param {function} forkedTypeScriptTypesCheckOptionsCallback
* @returns {Encore}
*/
enableForkedTypeScriptTypesChecking(forkedTypeScriptTypesCheckOptionsCallback = () => {}) {
webpackConfig.enableForkedTypeScriptTypesChecking(
forkedTypeScriptTypesCheckOptionsCallback
);
return this;
}
/**
* If enabled, a TypeScript preset will be applied to
* the generated Webpack and Babel configuration.
*
* ```
* Encore.enableBabelTypeScriptPreset()
* ```
*
* This method lets Babel handle your TypeScript code
* and cannot be used with `Encore.enableTypeScriptLoader()`
* or `Encore.enableForkedTypeScriptTypesChecking()`.
*
* Since all types are removed by Babel,
* you must run `tsc --noEmit` yourself for type checking.
*
* The Babel TypeScript preset can be configured,
* see https://babeljs.io/docs/en/babel-preset-typescript#options
* for available options.
*
* For example:
* ```
* Encore.enableBabelTypeScriptPreset({
* isTSX: true
* })
* ```
*
* @param {object} options
* @returns {Encore}
*/
enableBabelTypeScriptPreset(options = {}) {
webpackConfig.enableBabelTypeScriptPreset(options);
return this;
}
/**
* If enabled, the Vue.js loader is enabled.
*
* https://github.com/vuejs/vue-loader
*
* ```
* Encore.enableVueLoader();
*
* // or configure the vue-loader options
* // https://vue-loader.vuejs.org/en/configurations/advanced.html
* Encore.enableVueLoader(function(options) {
* options.preLoaders = { ... }
* });
* ```
*
* ```
* // or configure Encore-specific options
* Encore.enableVueLoader(() => {}, {
* // set optional Encore-specific options, for instance:
*
* // set to false to *only* include the smaller "runtime"
* // build, which can't compile templates at runtime, but is
* // CSP compliant/
* // set explicitly to true to silence the recommendation
* runtimeCompilerBuild: false
*
* // use version 2 or 3 to force your Vue version
* // otherwise, Encore will detect it automatically
* version: 2
*
* // enable JSX usage in Vue components
* // https://vuejs.org/v2/guide/render-function.html#JSX
* useJsx: true
* })
* ```
*
* Supported options:
* * {boolean} useJsx (default=false)
* Configure Babel to use the preset "@vue/babel-preset-jsx",
* in order to enable JSX usage in Vue components.
*
* @param {function} vueLoaderOptionsCallback
* @param {object} encoreOptions
* @returns {Encore}
*/
enableVueLoader(vueLoaderOptionsCallback = () => {}, encoreOptions = {}) {
webpackConfig.enableVueLoader(vueLoaderOptionsCallback, encoreOptions);
return this;
}
/**
* If enabled, the eslint-webpack-plugin is enabled.
*
* https://github.com/webpack-contrib/eslint-webpack-plugin
*
* ```
* // enables the eslint plugin using the default eslint configuration.
* Encore.enableEslintPlugin();
*
* // You can also pass in an object of options
* // that will be passed on to the eslint-webpack-plugin
* Encore.enableEslintPlugin({
* emitWarning: false
* });
*
* // For a more advanced usage you can pass in a callback
* // https://github.com/webpack-contrib/eslint-webpack-plugin#options
* Encore.enableEslintPlugin((options) => {
* options.extensions.push('vue'); // to lint Vue files
* options.emitWarning = false;
* });
* ```
*
* @param {string|object|function} eslintPluginOptionsOrCallback
* @returns {Encore}
*/
enableEslintPlugin(eslintPluginOptionsOrCallback = () => {}) {
webpackConfig.enableEslintPlugin(eslintPluginOptionsOrCallback);
return this;
}
/**
* If enabled, display build notifications using
* webpack-notifier.
*
* https://github.com/Turbo87/webpack-notifier
*
* ```
* Encore.enableBuildNotifications();
*
* // or configure the webpack-notifier options
* // https://github.com/Turbo87/webpack-notifier#configuration
* Encore.enableBuildNotifications(true, function(options) {
* options.title = 'Webpack build';
* });
* ```
*
* @param {boolean} enabled
* @param {function} notifierPluginOptionsCallback
* @returns {Encore}
*/
enableBuildNotifications(enabled = true, notifierPluginOptionsCallback = () => {}) {
webpackConfig.enableBuildNotifications(enabled, notifierPluginOptionsCallback);
return this;
}
/**
* Call this if you plan on loading Handlebars files.
*
* ```
* Encore.enableHandlebarsLoader();
* ```
*
* Or pass options to the loader
*
* ```
* Encore.enableHandlebarsLoader(function(options) {
* // https://github.com/pcardune/handlebars-loader
* // options.debug = true;
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
enableHandlebarsLoader(callback = () => {}) {
webpackConfig.enableHandlebarsLoader(callback);
return this;
}
/**
* Call this if you don't want imported CSS to be extracted
* into a .css file. All your styles will then be injected
* into the page by your JS code.
*
* This can be useful when using the dev-server with hot
* module reload (so that CSS can benefit from HMR):
*
* ```
* // disable CSS only when using the dev-server
* Encore.disableCssExtraction(Encore.isDevServer())
* ```
*
* Internally, this disables the mini-css-extract-plugin
* and uses the style-loader instead.
* @param {boolean} disabled
* @returns {Encore}
*/
disableCssExtraction(disabled = true) {
webpackConfig.disableCssExtraction(disabled);
return this;
}
/**
* Configure the style-loader.
* The style-loader is used only if you also call Encore. disableCssExtraction().
*
* https://github.com/webpack-contrib/style-loader#options
*
* ```
* Encore.configureStyleLoader(function(config) {
* // change the config
* // config.injectType = 'singletonStyleTag';
* });
* ```
*
* @param {function} callback
* @returns {Encore}
*/
configureStyleLoader(callback) {
webpackConfig.configureStyleLoader(callback);
return this;
}
/**
* Call this to change how the name of each output
* file is generated.
*
* ```
* Encore.configureFilenames({
* js: '[name].[contenthash].js',
* css: '[name].[contenthash].css',
* assets: 'assets/[name].[hash:8][ext]',
* });
* ```
*
* It's safe to omit a key (e.g. css): the default naming strategy
* will be used for any file types not passed.
*
* If you are using Encore.enableVersioning()
* make sure that your "js" and "css" filenames contain
* "[contenthash]".
*
* The "assets" key is used for the output.assetModuleFilename option,
* which is overridden for both fonts and images. See configureImageRule()
* and configureFontRule() to control those filenames.
*
* @param {object} filenames
* @returns {Encore}
*/
configureFilenames(filenames) {
webpackConfig.configureFilenames(filenames);
return this;
}
/**
* Configure how images are loaded/processed under module.rules.
*
* https://webpack.js.org/guides/asset-modules/
*
* The most important things can be controlled by passing
* an options object to the first argument:
*
* ```
* Encore.configureImageRule({
* // common values: asset, asset/resource, asset/inline
* // Using "asset" will allow smaller images to be "inlined"
* // instead of copied.
* // javascript/auto can be used to disable asset images (see next example)
* type: 'asset/resource',
*
* // applicable when for "type: asset": files smaller than this
* // size will be "inlined" into CSS, larger files will be extracted
* // into independent files
* maxSize: 4 * 1024, // 4 kb
*
* // control the output filename of images
* filename: 'images/[name].[hash:8][ext]',
*
* // you can also fully disable the image rule if you want
* // to control things yourself
* enabled: true,
* });
* ```
*
* If you need more control, you can also pass a callback to the
* 2nd argument. This will be passed the specific Rule object,
* which you can modify:
*
* https://webpack.js.org/configuration/module/#rule
*
* ```
* Encore.configureImageRule({}, function(rule) {
* // if you set "type: 'javascript/auto'" in the first argument,
* // then you can now specify a loader manually
* // rule.loader = 'file-loader';
* // rule.options = { filename: 'images/[name].[hash:8][ext]' }
* });
* ```
*
* @param {object} options
* @param {string|object|function} ruleCallback
* @returns {Encore}
*/
configureImageRule(options = {}, ruleCallback = (rule) => {}) {
webpackConfig.configureImageRule(options, ruleCallback);
return this;
}
/**
* Configure how fonts are processed/loaded under module.rules.
*
* https://webpack.js.org/guides/asset-modules/
*
* See configureImageRule() for more details.
*
* @param {object} options
* @param {string|object|function} ruleCallback
* @returns {Encore}
*/
configureFontRule(options = {}, ruleCallback = (rule) => {}) {
webpackConfig.configureFontRule(options, ruleCallback);
return this;
}
/**
* Configure Webpack loaders rules (`module.rules`).
* This is a low-level function, be careful when using it.
*
* https://webpack.js.org/concepts/loaders/#configuration
*
* ```
* Encore
* .enableVueLoader()
* .configureLoaderRule('vue', (loaderRule) => {
* // some custom config for vue-loader
* });
* ```
*
* @param {string} name
* @param {function} callback
* @return {Encore}
*/
configureLoaderRule(name, callback) {
webpackConfig.configureLoaderRule(name, callback);
return this;
}
/**
* If enabled, the output directory is emptied between each build (to remove old files).
*
* A list of available options can be found at https://github.com/johnagan/clean-webpack-plugin
*
* For example:
*
* ```
* Encore.cleanupOutputBeforeBuild(['*.js'], (options) => {
* options.dry = true;
* })
* ```
*
* @param {Array} paths Paths that should be cleaned, relative to the "root" option
* @param {function} cleanWebpackPluginOptionsCallback
* @returns {Encore}
*/
cleanupOutputBeforeBuild(paths = ['**/*'], cleanWebpackPluginOptionsCallback = () => {}) {
webpackConfig.cleanupOutputBeforeBuild(paths, cleanWebpackPluginOptionsCallback);
return this;
}
/**
* If enabled, add integrity hashes to the entrypoints.json
* file for all the files it references.
*
* These hashes can then be used, for instance, in the "integrity"
* attributes of <script> and <style> tags to enable subresource-
* integrity checks in the browser.
*
* https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
*
* For example:
*
* ```
* Encore.enableIntegrityHashes(
* Encore.isProduction(),
* 'sha384'
* );
* ```
*
* Or with multiple algorithms:
*
* ```
* Encore.enableIntegrityHashes(
* Encore.isProduction(),
* ['sha256', 'sha384', 'sha512']
* );
* ```
*
* @param {boolean} enabled
* @param {string|Array} algorithms
* @returns {Encore}
*/
enableIntegrityHashes(enabled = true, algorithms = ['sha384']) {
webpackConfig.enableIntegrityHashes(enabled, algorithms);
return this;
}
/**
* Is this currently a "production" build?
*
* @returns {boolean}
*/
isProduction() {
return webpackConfig.isProduction();
}
/**
* Is this currently a "dev" build?
*
* @returns {boolean}
*/
isDev() {
return webpackConfig.isDev();
}
/**
* Is this currently a "dev-server" build?
*
* @returns {boolean}
*/
isDevServer() {
return webpackConfig.isDevServer();
}
/**
* Use to conditionally configure or enable features only when the first parameter results to "true".
*
* ```
* Encore
* // passing a callback
* .when((Encore) => Encore.isProduction(), (Encore) => Encore.enableVersioning())
* // passing a boolean
* .when(process.argv.includes('--analyze'), (Encore) => Encore.addPlugin(new BundleAnalyzerPlugin()))
* ```
*
* @param {(function(Encore): boolean) | boolean} condition
* @param {function(Encore): void} callback
* @return {Encore}
*/
when(condition, callback) {
if (typeof condition === 'function' && condition(this) || typeof condition === 'boolean' && condition) {
callback(this);
}
return this;
}
/**
* Use this at the bottom of your webpack.config.js file:
*
* ```
* module.exports = Encore.getWebpackConfig();
* ```
*
* @returns {webpack.Configuration}
*/
getWebpackConfig() {
validator(webpackConfig);
return configGenerator(webpackConfig);
}
/**
* Resets the Encore state to allow building a new config.
*
* getWebpackConfig should be used before resetting to build
* a config for the existing state.
*
* @returns {void}
*/
reset() {
webpackConfig = new WebpackConfig(runtimeConfig);
}
/**
* Initialize the runtime environment.
*
* This can be used to configure the Encore runtime if you're
* using Encore without executing the "./node_module/.bin/encore"
* utility (e.g. with karma-webpack).
*
* ```
* Encore.configureRuntimeEnvironment(
* // Environment to use (dev, dev-server, production)
* 'dev-server',
*
* // Same options you would use with the
* // CLI utility with their name in
* // camelCase.
* {
* https: true,
* keepPublicPath: true
* }
* )
* ```
*
* Be aware than using this method will also reset the current
* webpack configuration.
*
* @param {string} environment
* @param {object} options
* @param {boolean} enablePackageJsonCheck
* @returns {Encore}
*/
configureRuntimeEnvironment(environment, options = {}, enablePackageJsonCheck = true) {
runtimeConfig = parseRuntime(
Object.assign(
{},
require('yargs-parser')([environment]),
options
),
process.cwd()
);
webpackConfig = new WebpackConfig(runtimeConfig, enablePackageJsonCheck);
return this;
}
/**
* Check if Encore was either called through
* the CLI utility or after being manually intialized
* using Encore.configureRuntimeEnvironment.
*
* @returns {boolean}
*/
isRuntimeEnvironmentConfigured() {
return runtimeConfig !== null;
}
/**
* Clear the runtime environment.
*
* Be aware than using this method will also reset the
* current webpack configuration.
*
* @returns {void}
*/
clearRuntimeEnvironment() {
runtimeConfig = null;
webpackConfig = null;
}
/**
* If enabled, the SvelteJs loader is enabled.
*
* https://github.com/sveltejs/svelte-loader
*
* @returns {Encore}
*/
enableSvelte() {
webpackConfig.enableSvelte();
return this;
}
}
/**
* Proxy the API in order to prevent calls to most of its methods
* if the webpackConfig object hasn't been initialized yet.
* @type {Encore}
*/
module.exports = EncoreProxy.createProxy(new Encore());