diff --git a/CHANGELOG.md b/CHANGELOG.md index 01961f55..a40f3fb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,56 @@ # CHANGELOG +## 1.0.0 + + * [DEPENDENCY UPGRADE] Webpack was upgraded from version 4 to 5. + + * [BC BREAK] Image and font processing was changed from using `file-loader` + (and optionally `url-loader` via `configureUrlLoader()`) to Webpack 5's + new [Asset Modules](https://webpack.js.org/guides/asset-modules/). + In practice, unless you have a highly-configured system, this should + not cause significant changes. + + * [BC BREAK] The `configureUrlLoader()` method was removed. See + `configureImageRule()` and `configureFontRule()` - specifically the + `maxSize` option and type: 'asset'. The `url-loader` is no longer used. + + * [BC BREAK] The `disableImagesLoader()` and `disableFontsLoader()` methods + have been removed. See `configureImageRule()` and `configureFontRule()` + for a new option to disable these. + + * [BC BREAK] The `configureFilenames()` method no longer accepts paths + for `images` or `fonts`. See `configureImageRule()` and `configureFontRule()` + for how to configure these filenames. The `configureFilenames()` method + *does* now accept an `assets` option, but out-of-the-box, this will not + result in any filename changes. See `configureFilenames()` for more details. + +* [BC BREAK] `css-minimizer-webpack-plugin` was replaced by + `css-minimizer-webpack-plugin` and the `optimizeCssPluginOptionsCallback()` + method was replaced by `cssMinimizerPluginOptionsCallback()`. + +* [BC BREAK] The `file-loader` package is no longer required by Encore. If + you use `copyFiles()`, you will need to install it manually (you + will receive a clear error about this). + +* [BC BREAK] All previously-deprecated methods & options were removed. + +* [DEPENDENCY UPGRADES] The following packages had major version upgrades: + * `css-loader` from 3 to 5 + * `mini-css-extract-plugin` from 0.4 to 1 + * `style-loader` from 1 to 2 + * `terser-webpack-plugin` from 1 to 4 + * `webpack-cli` from 3 to 4 + * `webpack-manifest-plugin` from 2 to 3 + +* [BEHAVIOR CHANGE] The `HashedModuleIdsPlugin` was previously used to + help name "modules" when building for production. This has been removed + and we now use Webpack's native `optimization.moduleIds` option, which + is set to `deterministic`. + +* [configureMiniCssExtractPlugin()] `configureMiniCssExtractPlugin()` was + added to allow the `MiniCssExtractPlugin.loader` and `MiniCssExtractPlugin` + to be configured. + ## 0.33.0 * [disableCssExtraction()] Added boolean argument to `disableCssExtraction()` diff --git a/index.js b/index.js index a75e9ecb..81385b5d 100644 --- a/index.js +++ b/index.js @@ -1299,30 +1299,6 @@ class Encore { return this; } - /** - * Call this if you wish to disable the default - * images loader. - * - * @returns {Encore} - */ - disableImagesLoader() { - webpackConfig.disableImagesLoader(); - - return this; - } - - /** - * Call this if you wish to disable the default - * fonts loader. - * - * @returns {Encore} - */ - disableFontsLoader() { - webpackConfig.disableFontsLoader(); - - 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 @@ -1377,8 +1353,7 @@ class Encore { * Encore.configureFilenames({ * js: '[name].[contenthash].js', * css: '[name].[contenthash].css', - * images: 'images/[name].[hash:8].[ext]', - * fonts: 'fonts/[name].[hash:8].[ext]' + * assets: 'assets/[name].[hash:8][ext]', * }); * ``` * @@ -1389,6 +1364,10 @@ class Encore { * 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} */ @@ -1399,30 +1378,73 @@ class Encore { } /** - * Allows to configure the URL loader. + * Configure how images are loaded/processed under module.rules. + * + * https://webpack.js.org/guides/asset-modules/ * - * https://github.com/webpack-contrib/url-loader + * The most important things can be controlled by passing + * an options object to the first argument: * * ``` - * Encore.configureUrlLoader({ - * images: { - * limit: 8192, - * mimetype: 'image/png' - * }, - * fonts: { - * limit: 4096 - * } + * Encore.configureImageRule({ + * // common values: asset, asset/resource, asset/inline + * // Using "asset" will allow smaller images to be "inlined" + * // instead of copied. + * // javascript/auto caan 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, larer 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 a key (e.g. fonts) doesn't exists or contains a - * falsy value the file-loader will be used instead. + * 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: * - * @param {object} urlLoaderOptions - * @return {Encore} + * 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} */ - configureUrlLoader(urlLoaderOptions = {}) { - webpackConfig.configureUrlLoader(urlLoaderOptions); + configureFontRule(options = {}, ruleCallback = (rule) => {}) { + webpackConfig.configureFontRule(options, ruleCallback); return this; } @@ -1597,9 +1619,10 @@ class Encore { * * @param {string} environment * @param {object} options + * @param {boolean} enablePackageJsonCheck * @returns {Encore} */ - configureRuntimeEnvironment(environment, options = {}) { + configureRuntimeEnvironment(environment, options = {}, enablePackageJsonCheck = true) { runtimeConfig = parseRuntime( Object.assign( {}, @@ -1609,7 +1632,7 @@ class Encore { process.cwd() ); - webpackConfig = new WebpackConfig(runtimeConfig, true); + webpackConfig = new WebpackConfig(runtimeConfig, enablePackageJsonCheck); return this; } diff --git a/lib/WebpackConfig.js b/lib/WebpackConfig.js index 08d0e3e5..183d5835 100644 --- a/lib/WebpackConfig.js +++ b/lib/WebpackConfig.js @@ -97,8 +97,18 @@ class WebpackConfig { this.useSourceMaps = false; this.cleanupOutput = false; this.extractCss = true; - this.useImagesLoader = true; - this.useFontsLoader = true; + this.imageRuleOptions = { + type: 'asset/resource', + maxSize: null, + filename: 'images/[name].[hash:8][ext]', + enabled: true, + }; + this.fontRuleOptions = { + type: 'asset/resource', + maxSize: null, + filename: 'fonts/[name].[hash:8][ext]', + enabled: true, + }; this.usePostCssLoader = false; this.useLessLoader = false; this.useStylusLoader = false; @@ -126,10 +136,6 @@ class WebpackConfig { this.preactOptions = { preactCompat: false }; - this.urlLoaderOptions = { - images: false, - fonts: false - }; this.babelOptions = { exclude: /(node_modules|bower_components)/, useBuiltIns: false, @@ -146,6 +152,8 @@ class WebpackConfig { }; // Features/Loaders options callbacks + this.imageRuleCallback = () => {}; + this.fontRuleCallback = () => {}; this.postCssLoaderOptionsCallback = () => {}; this.sassLoaderOptionsCallback = () => {}; this.lessLoaderOptionsCallback = () => {}; @@ -813,14 +821,6 @@ class WebpackConfig { this.handlebarsConfigurationCallback = callback; } - disableImagesLoader() { - this.useImagesLoader = false; - } - - disableFontsLoader() { - this.useFontsLoader = false; - } - disableCssExtraction(disabled = true) { this.extractCss = !disabled; } @@ -831,30 +831,54 @@ class WebpackConfig { } // Check allowed keys - const validKeys = ['js', 'css', 'images', 'fonts']; + const validKeys = ['js', 'css', 'assets']; for (const key of Object.keys(configuredFilenames)) { if (!validKeys.includes(key)) { - throw new Error(`"${key}" is not a valid key for configureFilenames(). Valid keys: ${validKeys.join(', ')}.`); + throw new Error(`"${key}" is not a valid key for configureFilenames(). Valid keys: ${validKeys.join(', ')}. Use configureImageRule() or configureFontRule() to control image or font filenames.`); } } this.configuredFilenames = configuredFilenames; } - configureUrlLoader(urlLoaderOptions = {}) { - if (typeof urlLoaderOptions !== 'object') { - throw new Error('Argument 1 to configureUrlLoader() must be an object.'); + configureImageRule(options = {}, ruleCallback = () => {}) { + for (const optionKey of Object.keys(options)) { + if (!(optionKey in this.imageRuleOptions)) { + throw new Error(`Invalid option "${optionKey}" passed to configureImageRule(). Valid keys are ${Object.keys(this.imageRuleOptions).join(', ')}`); + } + + this.imageRuleOptions[optionKey] = options[optionKey]; } - // Check allowed keys - const validKeys = ['images', 'fonts']; - for (const key of Object.keys(urlLoaderOptions)) { - if (!validKeys.includes(key)) { - throw new Error(`"${key}" is not a valid key for configureUrlLoader(). Valid keys: ${validKeys.join(', ')}.`); + if (this.imageRuleOptions.maxSize && this.imageRuleOptions.type !== 'asset') { + throw new Error('Invalid option "maxSize" passed to configureImageRule(): this option is only valid when "type" is set to "asset".'); + } + + if (typeof ruleCallback !== 'function') { + throw new Error('Argument 2 to configureImageRule() must be a callback function.'); + } + + this.imageRuleCallback = ruleCallback; + } + + configureFontRule(options = {}, ruleCallback = () => {}) { + for (const optionKey of Object.keys(options)) { + if (!(optionKey in this.fontRuleOptions)) { + throw new Error(`Invalid option "${optionKey}" passed to configureFontRule(). Valid keys are ${Object.keys(this.fontRuleOptions).join(', ')}`); } + + this.fontRuleOptions[optionKey] = options[optionKey]; + } + + if (this.fontRuleOptions.maxSize && this.fontRuleOptions.type !== 'asset') { + throw new Error('Invalid option "maxSize" passed to configureFontRule(): this option is only valid when "type" is set to "asset".'); + } + + if (typeof ruleCallback !== 'function') { + throw new Error('Argument 2 to configureFontRule() must be a callback function.'); } - this.urlLoaderOptions = urlLoaderOptions; + this.fontRuleCallback = ruleCallback; } cleanupOutputBeforeBuild(paths = ['**/*'], cleanWebpackPluginOptionsCallback = () => {}) { diff --git a/lib/config-generator.js b/lib/config-generator.js index 3ddef538..b3260806 100644 --- a/lib/config-generator.js +++ b/lib/config-generator.js @@ -12,7 +12,7 @@ const WebpackConfig = require('./WebpackConfig'); //eslint-disable-line no-unused-vars const cssExtractLoaderUtil = require('./loaders/css-extract'); const pathUtil = require('./config/path-util'); -const loaderFeatures = require('./features'); +const featuresHelper = require('./features'); // loaders utils const cssLoaderUtil = require('./loaders/css'); const sassLoaderUtil = require('./loaders/sass'); @@ -140,6 +140,10 @@ class ConfigGenerator { entry[entryName] = entryChunks; } + if (this.webpackConfig.copyFilesConfigs.length > 0) { + featuresHelper.ensurePackagesExistAndAreCorrectVersion('copy_files'); + } + const copyFilesConfigs = this.webpackConfig.copyFilesConfigs.filter(entry => { const copyFrom = path.resolve( this.webpackConfig.getContext(), @@ -215,6 +219,9 @@ class ConfigGenerator { return { path: this.webpackConfig.outputPath, filename: filename, + // default "asset module" filename + // this is overridden for the image & font rules + assetModuleFilename: this.webpackConfig.configuredFilenames.assets ? this.webpackConfig.configuredFilenames.assets : 'assets/[name].[hash:8][ext]', // will use the CDN path (if one is available) so that split // chunks load internally through the CDN. publicPath: this.webpackConfig.getRealPublicPath(), @@ -227,6 +234,33 @@ class ConfigGenerator { return applyOptionsCallback(this.webpackConfig.loaderConfigurationCallbacks[name], defaultRules); }; + const generateAssetRuleConfig = (testRegex, ruleOptions, ruleCallback, ruleName) => { + const generatorOptions = {}; + if (ruleOptions.filename) { + generatorOptions.filename = ruleOptions.filename; + } + const parserOptions = {}; + if (ruleOptions.maxSize) { + parserOptions.dataUrlCondition = { + maxSize: ruleOptions.maxSize, + }; + } + + // apply callback from, for example, configureImageRule() + const ruleConfig = applyOptionsCallback( + ruleCallback, + { + test: testRegex, + type: ruleOptions.type, + generator: generatorOptions, + parser: parserOptions, + }, + ); + + // apply callback from lower-level configureLoaderRule() + return applyRuleConfigurationCallback(ruleName, ruleConfig); + }; + // When the PostCSS loader is enabled, allow to use // files with the `.postcss` extension. It also // makes it possible to use `lang="postcss"` in Vue @@ -267,60 +301,22 @@ class ConfigGenerator { }) ]; - if (this.webpackConfig.useImagesLoader) { - // Default filename can be overridden using Encore.configureFilenames({ images: '...' }) - let filename = 'images/[name].[hash:8].[ext]'; - if (this.webpackConfig.configuredFilenames.images) { - filename = this.webpackConfig.configuredFilenames.images; - } - - // The url-loader can be used instead of the default file-loader by - // calling Encore.configureUrlLoader({ images: {/* ... */}}) - let loaderName = 'file-loader'; - const loaderOptions = { - name: filename, - publicPath: this.webpackConfig.getRealPublicPath() - }; - - if (this.webpackConfig.urlLoaderOptions.images) { - loaderFeatures.ensurePackagesExistAndAreCorrectVersion('urlloader'); - loaderName = 'url-loader'; - Object.assign(loaderOptions, this.webpackConfig.urlLoaderOptions.images); - } - - rules.push(applyRuleConfigurationCallback('images', { - test: /\.(png|jpg|jpeg|gif|ico|svg|webp)$/, - loader: require.resolve(loaderName), - options: loaderOptions - })); + if (this.webpackConfig.imageRuleOptions.enabled) { + rules.push(generateAssetRuleConfig( + /\.(png|jpg|jpeg|gif|ico|svg|webp)$/, + this.webpackConfig.imageRuleOptions, + this.webpackConfig.imageRuleCallback, + 'images' + )); } - if (this.webpackConfig.useFontsLoader) { - // Default filename can be overridden using Encore.configureFilenames({ fonts: '...' }) - let filename = 'fonts/[name].[hash:8].[ext]'; - if (this.webpackConfig.configuredFilenames.fonts) { - filename = this.webpackConfig.configuredFilenames.fonts; - } - - // The url-loader can be used instead of the default file-loader by - // calling Encore.configureUrlLoader({ fonts: {/* ... */}}) - let loaderName = 'file-loader'; - const loaderOptions = { - name: filename, - publicPath: this.webpackConfig.getRealPublicPath() - }; - - if (this.webpackConfig.urlLoaderOptions.fonts) { - loaderFeatures.ensurePackagesExistAndAreCorrectVersion('urlloader'); - loaderName = 'url-loader'; - Object.assign(loaderOptions, this.webpackConfig.urlLoaderOptions.fonts); - } - - rules.push(applyRuleConfigurationCallback('fonts', { - test: /\.(woff|woff2|ttf|eot|otf)$/, - loader: require.resolve(loaderName), - options: loaderOptions - })); + if (this.webpackConfig.fontRuleOptions.enabled) { + rules.push(generateAssetRuleConfig( + /\.(woff|woff2|ttf|eot|otf)$/, + this.webpackConfig.fontRuleOptions, + this.webpackConfig.fontRuleCallback, + 'fonts' + )); } if (this.webpackConfig.useSassLoader) { diff --git a/lib/features.js b/lib/features.js index 0b87a9e9..6262f0c5 100644 --- a/lib/features.js +++ b/lib/features.js @@ -126,6 +126,13 @@ const features = { ], description: 'Enable ESLint checks' }, + copy_files: { + method: 'copyFiles()', + packages: [ + { name: 'file-loader', enforce_version: true }, + ], + description: 'Copy files' + }, notifier: { method: 'enableBuildNotifications()', packages: [ @@ -133,13 +140,6 @@ const features = { ], description: 'display build notifications' }, - urlloader: { - method: 'configureUrlLoader()', - packages: [ - { name: 'url-loader', enforce_version: true }, - ], - description: 'use the url-loader' - }, handlebars: { method: 'enableHandlebarsLoader()', packages: [ diff --git a/lib/package-helper.js b/lib/package-helper.js index afef5166..b531562a 100644 --- a/lib/package-helper.js +++ b/lib/package-helper.js @@ -177,6 +177,12 @@ function addPackagesVersionConstraint(packages) { const newData = Object.assign({}, packageData); if (packageData.enforce_version) { + if (!packageJsonData.devDependencies) { + logger.warning('Could not find devDependencies key on @symfony/webpack-encore package'); + + return newData; + } + // this method only supports devDependencies due to how it's used: // it's mean to inform the user what deps they need to install // for optional features diff --git a/lib/webpack/copy-files-loader.js b/lib/webpack/copy-files-loader.js index 608fb48a..d95341e2 100644 --- a/lib/webpack/copy-files-loader.js +++ b/lib/webpack/copy-files-loader.js @@ -10,7 +10,6 @@ 'use strict'; const LoaderDependency = require('webpack/lib/dependencies/LoaderDependency'); -const fileLoader = require('file-loader'); const loaderUtils = require('loader-utils'); const path = require('path'); @@ -86,6 +85,8 @@ module.exports.default = function loader(source) { } }); + const fileLoader = require('file-loader'); // eslint-disable-line node/no-unpublished-require + // If everything is OK, let the file-loader do the copy return fileLoader.bind(this)(source); }; diff --git a/package.json b/package.json index 0e13efce..6c02ad9e 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "css-loader": "^5.0.1", "css-minimizer-webpack-plugin": "^1.1.5", "fast-levenshtein": "^2.0.6", - "file-loader": "^6.0.0", "friendly-errors-webpack-plugin": "^2.0.0-beta.1", "loader-utils": "^2.0.0", "mini-css-extract-plugin": "^1.0.0", @@ -46,7 +45,7 @@ "style-loader": "^2.0.0", "terser-webpack-plugin": "^4.2.3", "tmp": "^0.2.1", - "webpack": "^5", + "webpack": "^5.12", "webpack-cli": "^4", "webpack-dev-server": "^3.1.14", "webpack-manifest-plugin": "^3", @@ -77,6 +76,7 @@ "eslint-plugin-header": "^1.0.0", "eslint-plugin-import": "^2.8.0", "eslint-plugin-node": "^8.0.1", + "file-loader": "^6.0.0", "fork-ts-checker-webpack-plugin": "^4.0.0", "fs-extra": "^9.0.0", "handlebars": "^4.0.11", @@ -97,7 +97,6 @@ "stylus-loader": "^3.0.2", "ts-loader": "^8.0.1", "typescript": ">=3.6.3", - "url-loader": "^4.1.0", "vue": "^3.0.2", "vue-loader": "^16.1.0", "vue-template-compiler": "^2.5", diff --git a/test/WebpackConfig.js b/test/WebpackConfig.js index c9f78e4a..a9166170 100644 --- a/test/WebpackConfig.js +++ b/test/WebpackConfig.js @@ -1226,24 +1226,6 @@ describe('WebpackConfig object', () => { }); }); - describe('disableImagesLoader', () => { - it('Disable default images loader', () => { - const config = createConfig(); - config.disableImagesLoader(); - - expect(config.useImagesLoader).to.be.false; - }); - }); - - describe('disableFontsLoader', () => { - it('Disable default fonts loader', () => { - const config = createConfig(); - config.disableFontsLoader(); - - expect(config.useFontsLoader).to.be.false; - }); - }); - describe('disableCssExtraction', () => { it('By default the CSS extraction is enabled', () => { const config = createConfig(); @@ -1280,15 +1262,13 @@ describe('WebpackConfig object', () => { config.configureFilenames({ js: '[name].[contenthash].js', css: '[name].[contenthash].css', - images: 'images/[name].[hash:8].[ext]', - fonts: 'fonts/[name].[hash:8].[ext]' + assets: 'assets/[name].[hash:8][ext]', }); expect(config.configuredFilenames).to.deep.equals({ js: '[name].[contenthash].js', css: '[name].[contenthash].css', - images: 'images/[name].[hash:8].[ext]', - fonts: 'fonts/[name].[hash:8].[ext]' + assets: 'assets/[name].[hash:8][ext]', }); }); @@ -1311,36 +1291,79 @@ describe('WebpackConfig object', () => { }); }); - describe('configureUrlLoader', () => { - it('Calling method sets it', () => { + describe('configureImageRule', () => { + it('Calling method sets options and callback', () => { const config = createConfig(); - config.configureUrlLoader({ - images: { limit: 8192 }, - fonts: { limit: 4096 } - }); + const callback = () => {}; + config.configureImageRule({ + type: 'asset', + maxSize: 1024, + }, callback); - expect(config.urlLoaderOptions).to.deep.equals({ - images: { limit: 8192 }, - fonts: { limit: 4096 } - }); + expect(config.imageRuleOptions.maxSize).to.equals(1024); + expect(config.imageRuleCallback).to.equals(callback); }); - it('Calling with non-object throws an error', () => { + it('Calling with invalid option throws error', () => { const config = createConfig(); expect(() => { - config.configureUrlLoader('FOO'); - }).to.throw('must be an object'); + config.configureImageRule({ fake: true }); + }).to.throw('Invalid option "fake" passed'); }); - it('Calling with an unknown key throws an error', () => { + it('Setting maxSize for type of not asset throws error', () => { const config = createConfig(); expect(() => { - config.configureUrlLoader({ - foo: 'bar' - }); - }).to.throw('"foo" is not a valid key'); + config.configureImageRule({ type: 'asset/resource', maxSize: 1024 }); + }).to.throw('this option is only valid when "type" is set to "asset"'); + }); + + it('Passing non callback to 2nd arg throws error', () => { + const config = createConfig(); + + expect(() => { + config.configureImageRule({}, {}); + }).to.throw('Argument 2 to configureImageRule() must be a callback'); + }); + }); + + describe('configureFontRule', () => { + it('Calling method sets options and callback', () => { + const config = createConfig(); + const callback = () => {}; + config.configureFontRule({ + type: 'asset', + maxSize: 1024, + }, callback); + + expect(config.fontRuleOptions.maxSize).to.equals(1024); + expect(config.fontRuleCallback).to.equals(callback); + }); + + it('Calling with invalid option throws error', () => { + const config = createConfig(); + + expect(() => { + config.configureFontRule({ fake: true }); + }).to.throw('Invalid option "fake" passed'); + }); + + it('Setting maxSize for type of not asset throws error', () => { + const config = createConfig(); + + expect(() => { + config.configureFontRule({ type: 'asset/resource', maxSize: 1024 }); + }).to.throw('this option is only valid when "type" is set to "asset"'); + }); + + it('Passing non callback to 2nd arg throws error', () => { + const config = createConfig(); + + expect(() => { + config.configureFontRule({}, {}); + }).to.throw('Argument 2 to configureFontRule() must be a callback'); }); }); diff --git a/test/config-generator.js b/test/config-generator.js index e862cdab..cef6da03 100644 --- a/test/config-generator.js +++ b/test/config-generator.js @@ -772,66 +772,6 @@ describe('The config-generator function', () => { }); }); - describe('disableImagesLoader() removes the default images loader', () => { - it('without disableImagesLoader()', () => { - const config = createConfig(); - config.outputPath = '/tmp/output/public-path'; - config.publicPath = '/public-path'; - config.addEntry('main', './main'); - // do not call disableImagesLoader - - const actualConfig = configGenerator(config); - - expect(function() { - findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); - }).to.not.throw(); - }); - - it('with disableImagesLoader()', () => { - const config = createConfig(); - config.outputPath = '/tmp/output/public-path'; - config.publicPath = '/public-path'; - config.addEntry('main', './main'); - config.disableImagesLoader(); - - const actualConfig = configGenerator(config); - - expect(function() { - findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); - }).to.throw(); - }); - }); - - describe('disableFontsLoader() removes the default fonts loader', () => { - it('without disableFontsLoader()', () => { - const config = createConfig(); - config.outputPath = '/tmp/output/public-path'; - config.publicPath = '/public-path'; - config.addEntry('main', './main'); - // do not call disableFontsLoader - - const actualConfig = configGenerator(config); - - expect(function() { - findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules); - }).to.not.throw(); - }); - - it('with disableFontsLoader()', () => { - const config = createConfig(); - config.outputPath = '/tmp/output/public-path'; - config.publicPath = '/public-path'; - config.addEntry('main', './main'); - config.disableFontsLoader(); - - const actualConfig = configGenerator(config); - - expect(function() { - findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules); - }).to.throw(); - }); - }); - describe('Test filenames changes', () => { it('without versioning', () => { const config = createConfig(); @@ -841,21 +781,16 @@ describe('The config-generator function', () => { config.configureFilenames({ js: '[name].foo.js', css: '[name].foo.css', - images: '[name].foo.[ext]', - fonts: '[name].bar.[ext]' + assets: '[name].assets[ext]', }); const actualConfig = configGenerator(config); expect(actualConfig.output.filename).to.equal('[name].foo.js'); + expect(actualConfig.output.assetModuleFilename).to.equal('[name].assets[ext]'); + const miniCssExtractPlugin = findPlugin(MiniCssExtractPlugin, actualConfig.plugins); expect(miniCssExtractPlugin.options.filename).to.equal('[name].foo.css'); - - const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); - expect(imagesRule.options.name).to.equal('[name].foo.[ext]'); - - const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules); - expect(fontsRule.options.name).to.equal('[name].bar.[ext]'); }); it('with versioning', () => { @@ -867,26 +802,21 @@ describe('The config-generator function', () => { config.configureFilenames({ js: '[name].foo.js', css: '[name].foo.css', - images: '[name].foo.[ext]', - fonts: '[name].bar.[ext]' + assets: '[name].assets[ext]', }); const actualConfig = configGenerator(config); expect(actualConfig.output.filename).to.equal('[name].foo.js'); + expect(actualConfig.output.assetModuleFilename).to.equal('[name].assets[ext]'); + const miniCssExtractPlugin = findPlugin(MiniCssExtractPlugin, actualConfig.plugins); expect(miniCssExtractPlugin.options.filename).to.equal('[name].foo.css'); - - const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); - expect(imagesRule.options.name).to.equal('[name].foo.[ext]'); - - const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules); - expect(fontsRule.options.name).to.equal('[name].bar.[ext]'); }); }); - describe('configureUrlLoader() allows to use the URL loader for fonts/images', () => { - it('without configureUrlLoader()', () => { + describe('configuration for assets (images and fonts)', () => { + it('no custom config', () => { const config = createConfig(); config.outputPath = '/tmp/public-path'; config.publicPath = '/public-path'; @@ -895,53 +825,63 @@ describe('The config-generator function', () => { const actualConfig = configGenerator(config); const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); - expect(imagesRule.loader).to.contain('file-loader'); + expect(imagesRule.type).to.equal('asset/resource'); + expect(imagesRule.generator).to.eql({ filename: 'images/[name].[hash:8][ext]' }); + expect(imagesRule.parser).to.eql({}); + expect(imagesRule).to.include.keys('test', 'type', 'generator', 'parser'); const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules); - expect(fontsRule.loader).to.contain('file-loader'); + expect(fontsRule.type).to.equal('asset/resource'); + expect(fontsRule.generator).to.eql({ filename: 'fonts/[name].[hash:8][ext]' }); }); - it('with configureUrlLoader() and missing keys', () => { + it('with configureImageRule() custom options', () => { const config = createConfig(); config.outputPath = '/tmp/public-path'; config.publicPath = '/public-path'; config.addEntry('main', './main'); - config.configureUrlLoader({}); + config.configureImageRule({ + type: 'asset/resource', + filename: 'file.[hash][ext]' + }); const actualConfig = configGenerator(config); const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); - expect(imagesRule.loader).to.contain('file-loader'); - - const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules); - expect(fontsRule.loader).to.contain('file-loader'); + expect(imagesRule.type).to.equal('asset/resource'); + expect(imagesRule.generator).to.eql({ filename: 'file.[hash][ext]' }); }); - it('with configureUrlLoader()', () => { + it('with configureImageRule() and maxSize', () => { const config = createConfig(); config.outputPath = '/tmp/public-path'; config.publicPath = '/public-path'; config.addEntry('main', './main'); - config.configureFilenames({ - images: '[name].foo.[ext]', - fonts: '[name].bar.[ext]' - }); - config.configureUrlLoader({ - images: { limit: 8192 }, - fonts: { limit: 4096 } + config.configureImageRule({ + type: 'asset', + maxSize: 3000, }); const actualConfig = configGenerator(config); const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); - expect(imagesRule.loader).to.contain('url-loader'); - expect(imagesRule.options.name).to.equal('[name].foo.[ext]'); - expect(imagesRule.options.limit).to.equal(8192); + expect(imagesRule.parser).to.eql({ dataUrlCondition: { maxSize: 3000 } }); + }); - const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules); - expect(fontsRule.loader).to.contain('url-loader'); - expect(fontsRule.options.limit).to.equal(4096); - expect(fontsRule.options.name).to.equal('[name].bar.[ext]'); + it('with configureImageRule() disabled', () => { + const config = createConfig(); + config.outputPath = '/tmp/public-path'; + config.publicPath = '/public-path'; + config.addEntry('main', './main'); + config.configureImageRule({ + enabled: false, + }); + + const actualConfig = configGenerator(config); + + expect(function() { + findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules); + }).to.throw(); }); }); @@ -1196,24 +1136,24 @@ describe('The config-generator function', () => { it('configure rule for "images"', () => { config.configureLoaderRule('images', (loaderRule) => { - loaderRule.options.name = 'dirname-images/[hash:42].[ext]'; + loaderRule.generator.filename = 'dirname-images/[hash:42][ext]'; }); const webpackConfig = configGenerator(config); const rule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, webpackConfig.module.rules); - expect(rule.options.name).to.equal('dirname-images/[hash:42].[ext]'); + expect(rule.generator.filename).to.equal('dirname-images/[hash:42][ext]'); }); it('configure rule for "fonts"', () => { config.configureLoaderRule('fonts', (loader) => { - loader.options.name = 'dirname-fonts/[hash:42].[ext]'; + loader.generator.filename = 'dirname-fonts/[hash:42][ext]'; }); const webpackConfig = configGenerator(config); const rule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, webpackConfig.module.rules); - expect(rule.options.name).to.equal('dirname-fonts/[hash:42].[ext]'); + expect(rule.generator.filename).to.equal('dirname-fonts/[hash:42][ext]'); }); it('configure rule for "sass"', () => { @@ -1355,7 +1295,6 @@ describe('The config-generator function', () => { config.publicPath = '/public-path'; config.enableSingleRuntimeChunk(); config.addEntry('main', './main'); - // do not call disableImagesLoader const actualConfig = configGenerator(config); diff --git a/test/functional.js b/test/functional.js index 4e5e2ca1..45ed008f 100644 --- a/test/functional.js +++ b/test/functional.js @@ -418,16 +418,13 @@ describe('Functional tests using webpack', function() { config.enableVersioning(true); testSetup.runWebpack(config, (webpackAssert) => { - if (!process.env.DISABLE_UNSTABLE_CHECKS) { - expect(config.outputPath).to.be.a.directory() - .with.files([ - 'main.8b8ca4a9.js', - 'styles.79943add.css', - 'manifest.json', - 'entrypoints.json', - 'runtime.49688a3c.js', - ]); - } + webpackAssert.assertDirectoryContents([ + 'main.[hash:8].js', + 'styles.[hash:8].css', + 'manifest.json', + 'entrypoints.json', + 'runtime.[hash:8].js', + ]); webpackAssert.assertOutputFileContains( 'styles.79943add.css', @@ -521,19 +518,16 @@ describe('Functional tests using webpack', function() { config.enableVersioning(true); testSetup.runWebpack(config, (webpackAssert) => { - if (!process.env.DISABLE_UNSTABLE_CHECKS) { - expect(config.outputPath).to.be.a.directory() - .with.files([ - 'js_no_require_js-css_h1_style_css.456c237a.js', // chunks are also versioned - 'js_no_require_js-css_h1_style_css.79943add.css', - 'main.04316e30.js', - 'h1.79943add.css', - 'bg.2eff0999.css', - 'manifest.json', - 'entrypoints.json', - 'runtime.d0652ec8.js', - ]); - } + webpackAssert.assertDirectoryContents([ + 'js_no_require_js-css_h1_style_css.[hash:8].js', // chunks are also versioned + 'js_no_require_js-css_h1_style_css.[hash:8].css', + 'main.[hash:8].js', + 'h1.[hash:8].css', + 'bg.[hash:8].css', + 'manifest.json', + 'entrypoints.json', + 'runtime.[hash:8].js', + ]); expect(path.join(config.outputPath, 'images')).to.be.a.directory() .with.files([ @@ -1745,14 +1739,13 @@ module.exports = { }); }); - it('configureUrlLoader() allows to use the URL loader for images/fonts', (done) => { + it('configureImageRule() allows configuring maxSize for inlining', (done) => { const config = createWebpackConfig('web/build', 'dev'); config.setPublicPath('/build'); config.addStyleEntry('url-loader', './css/url-loader.css'); - config.configureUrlLoader({ - images: { limit: 102400 }, - fonts: { limit: 102400 } - }); + // set a size so that they do NOT inline + config.configureImageRule({ type: 'asset', maxSize: 102400 }); + config.configureFontRule({ type: 'asset', maxSize: 102400 }); testSetup.runWebpack(config, (webpackAssert) => { expect(config.outputPath).to.be.a.directory() @@ -2168,22 +2161,19 @@ module.exports = { }]); testSetup.runWebpack(config, (webpackAssert) => { - if (!process.env.DISABLE_UNSTABLE_CHECKS) { - expect(config.outputPath).to.be.a.directory() - .with.files([ - 'entrypoints.json', - 'runtime.fbc90386.js', - 'main.06a6c20f.js', - 'manifest.json', - 'symfony_logo.91beba37.png', - 'symfony_logo_alt.f880ba14.png', - ]); - - webpackAssert.assertManifestPath( - 'build/main.js', - '/build/main.06a6c20f.js' - ); - } + webpackAssert.assertDirectoryContents([ + 'entrypoints.json', + 'runtime.fbc90386.js', + 'main.06a6c20f.js', + 'manifest.json', + 'symfony_logo.91beba37.png', + 'symfony_logo_alt.f880ba14.png', + ]); + + webpackAssert.assertManifestPath( + 'build/main.js', + '/build/main.[hash:8].js' + ); expect(path.join(config.outputPath, 'assets')).to.be.a.directory() .with.files([ diff --git a/test/helpers/assert.js b/test/helpers/assert.js index ba26755f..7d09c632 100644 --- a/test/helpers/assert.js +++ b/test/helpers/assert.js @@ -13,6 +13,7 @@ const path = require('path'); const fs = require('fs'); const chai = require('chai'); const expect = chai.expect; +const regexEscaper = require('../../lib/utils/regexp-escaper'); const loadManifest = function(webpackConfig) { return JSON.parse( @@ -30,6 +31,27 @@ const readOutputFile = function(webpackConfig, filePath) { return fs.readFileSync(fullPath, 'utf8'); }; +/** + * Returns a regex to use to match this filename + * + * @param {string} filename Filename with possible [hash:8] wildcard + * @return {RegExp} + */ +const convertFilenameToMatcher = function(filename) { + const hashMatch = filename.match(/\[hash:(\d+)\]/); + + if (hashMatch === null) { + return new RegExp(regexEscaper(filename)); + } + + const [hashString, hashLength] = hashMatch; + + return new RegExp( + regexEscaper(filename) + .replace(regexEscaper(hashString), `([a-z0-9_-]){${hashLength}}`) + ); +}; + class Assert { /** * @param {WebpackConfig} webpackConfig @@ -107,8 +129,10 @@ class Assert { this.assertManifestKeyExists(sourcePath); - if (manifestData[sourcePath] !== expectedDestinationPath) { - throw new Error(`source path ${sourcePath} expected to be set to ${expectedDestinationPath}, was actually ${manifestData[sourcePath]}`); + const expectedRegex = convertFilenameToMatcher(expectedDestinationPath); + + if (!manifestData[sourcePath].match(expectedRegex)) { + throw new Error(`source path ${sourcePath} expected to match pattern ${expectedDestinationPath}, was actually ${manifestData[sourcePath]}`); } } @@ -168,6 +192,57 @@ class Assert { expect(JSON.stringify(actualData, null, 2)).to.equal(JSON.stringify(expectedData, null, 2)); } + + /** + * Verifies that the directory contains the array of files. + * + * The expectedFiles can contain a [hash:8] syntax in case + * the file is versioned - e.g. main.[hash:8].js, which would + * match a real file like main.abcd1234.js. + * + * @param {Array} expectedFiles + * @param {string} directory relative to output to check + * @returns {void} + */ + assertDirectoryContents(expectedFiles, directory = '') { + const targetDirectory = path.join(this.webpackConfig.outputPath, directory); + + expect(targetDirectory).to.be.a.directory(); + + const expectedFileStrings = {}; + expectedFiles.forEach((expectedFile) => { + expectedFileStrings[expectedFile] = convertFilenameToMatcher(expectedFile); + }); + + const actualFiles = fs.readdirSync(targetDirectory); + actualFiles.forEach((foundFile) => { + // filter out directories + if (fs.statSync(path.join(targetDirectory, foundFile)).isDirectory()) { + return; + } + + let matchIsFound = false; + + for (const originalFilename of Object.keys(expectedFileStrings)) { + const filenameRegex = expectedFileStrings[originalFilename]; + + if (foundFile.match(filenameRegex)) { + matchIsFound = true; + delete expectedFileStrings[originalFilename]; + + break; + } + } + + if (!matchIsFound) { + throw new Error(`File "${foundFile}" was found in directory but was not expected. Expected patterns where ${expectedFiles.join(', ')}`); + } + }); + + if (Object.keys(expectedFileStrings).length > 0) { + throw new Error(`Files ${Object.keys(expectedFileStrings).join(', ')} were expected to be found in the directory but were not. Actual files: ${actualFiles.join(', ')}`); + } + } } module.exports = function(webpackConfig) { diff --git a/test/index.js b/test/index.js index a1f6ddcd..6cd0882e 100644 --- a/test/index.js +++ b/test/index.js @@ -14,7 +14,7 @@ const api = require('../index'); describe('Public API', () => { beforeEach(() => { - api.configureRuntimeEnvironment('dev'); + api.configureRuntimeEnvironment('dev', {}, false); }); describe('setOutputPath', () => { @@ -317,46 +317,37 @@ describe('Public API', () => { }); - describe('disableImagesLoader', () => { - - it('must return the API object', () => { - const returnedValue = api.disableImagesLoader(); - expect(returnedValue).to.equal(api); - }); - - }); - - describe('disableFontsLoader', () => { + describe('disableCssExtraction', () => { it('must return the API object', () => { - const returnedValue = api.disableFontsLoader(); + const returnedValue = api.disableCssExtraction(); expect(returnedValue).to.equal(api); }); }); - describe('disableCssExtraction', () => { + describe('configureFilenames', () => { it('must return the API object', () => { - const returnedValue = api.disableCssExtraction(); + const returnedValue = api.configureFilenames({}); expect(returnedValue).to.equal(api); }); }); - describe('configureFilenames', () => { + describe('configureImageRule', () => { it('must return the API object', () => { - const returnedValue = api.configureFilenames({}); + const returnedValue = api.configureImageRule(); expect(returnedValue).to.equal(api); }); }); - describe('configureUrlLoader', () => { + describe('configureFontRule', () => { it('must return the API object', () => { - const returnedValue = api.configureUrlLoader({}); + const returnedValue = api.configureFontRule(); expect(returnedValue).to.equal(api); }); diff --git a/test/package-helper.js b/test/package-helper.js index ac3b2fc1..62fa9406 100644 --- a/test/package-helper.js +++ b/test/package-helper.js @@ -123,7 +123,7 @@ describe('package-helper', () => { describe('The getInvalidPackageVersionRecommendations correctly checks installed versions', () => { it('Check package that *is* the correct version', () => { const versionProblems = packageHelper.getInvalidPackageVersionRecommendations([ - { name: 'sass-loader', version: '^10.1.0' }, + { name: 'stimulus', version: '^2.0.0' }, { name: 'preact', version: '^8.2.0' } ]); @@ -132,7 +132,7 @@ describe('package-helper', () => { it('Check package with a version too low', () => { const versionProblems = packageHelper.getInvalidPackageVersionRecommendations([ - { name: 'sass-loader', version: '^11.0.0' }, + { name: 'stimulus', version: '^3.0.0' }, { name: 'preact', version: '9.0.0' } ]); @@ -142,7 +142,7 @@ describe('package-helper', () => { it('Check package with a version too new', () => { const versionProblems = packageHelper.getInvalidPackageVersionRecommendations([ - { name: 'sass-loader', version: '^9.0.1' }, + { name: 'stimulus', version: '^1.6' }, { name: 'preact', version: '8.1.0' } ]); diff --git a/yarn.lock b/yarn.lock index 9be33a5b..d6d829b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -918,7 +918,7 @@ dependencies: mkdirp "^1.0.4" -"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": +"@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1": version "1.8.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw== @@ -932,15 +932,7 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@sinonjs/formatio@^5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089" - integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ== - dependencies: - "@sinonjs/commons" "^1" - "@sinonjs/samsam" "^5.0.2" - -"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.3.0": +"@sinonjs/samsam@^5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.0.tgz#1d2f0743dc54bf13fe9d508baefacdffa25d4329" integrity sha512-hXpcfx3aq+ETVBwPlRFICld5EnrkexXuXDwqUNhDdr5L8VjvMeSRwyOa0qL7XFmR+jVWR4rUZtnxlG7RX72sBg== @@ -1044,9 +1036,9 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "14.14.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.17.tgz#29fab92f3986c0e379968ad3c2043683d8020dbb" - integrity sha512-G0lD1/7qD60TJ/mZmhog76k7NcpLWkPVGgzkRy3CTlnFu4LUQh5v2Wa661z6vnXmD8EQrnALUyf0VRtrACYztw== + version "14.14.20" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.20.tgz#f7974863edd21d1f8a494a73e8e2b3658615c340" + integrity sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A== "@types/parse-json@^4.0.0": version "4.0.0" @@ -1508,6 +1500,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.0.3.tgz#13ae747eff125cafb230ac504b2406cf371eece2" + integrity sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + alphanum-sort@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -1966,16 +1968,16 @@ browserslist@^3.2.8: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.15.0: - version "4.16.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.0.tgz#410277627500be3cb28a1bfe037586fbedf9488b" - integrity sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ== +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.0: + version "4.16.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.1.tgz#bf757a2da376b3447b800a16f0f1c96358138766" + integrity sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA== dependencies: - caniuse-lite "^1.0.30001165" + caniuse-lite "^1.0.30001173" colorette "^1.2.1" - electron-to-chromium "^1.3.621" + electron-to-chromium "^1.3.634" escalade "^3.1.1" - node-releases "^1.1.67" + node-releases "^1.1.69" buffer-from@^1.0.0: version "1.1.1" @@ -2036,12 +2038,12 @@ cache-base@^1.0.1: unset-value "^1.0.0" call-bind@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" - integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w== + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.1.tgz#29aca9151f8ddcfd5b9b786898f005f425e88567" + integrity sha512-tvAvUwNcRikl3RVF20X9lsYmmepsovzTWeJiXjO0PkJp15uy/6xKFZOQtuiSULwYW+6ToZBprphCgWXC2dSgcQ== dependencies: function-bind "^1.1.1" - get-intrinsic "^1.0.0" + get-intrinsic "^1.0.2" call-me-maybe@^1.0.1: version "1.0.1" @@ -2092,10 +2094,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000864, caniuse-lite@^1.0.30001165: - version "1.0.30001171" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001171.tgz#3291e11e02699ad0a29e69b8d407666fc843eba7" - integrity sha512-5Alrh8TTYPG9IH4UkRqEBZoEToWRLvPbSQokvzSz0lii8/FOWKG4keO1HoYfPWs8IF/NH/dyNPg1cmJGvV3Zlg== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000864, caniuse-lite@^1.0.30001173: + version "1.0.30001173" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001173.tgz#3c47bbe3cd6d7a9eda7f50ac016d158005569f56" + integrity sha512-R3aqmjrICdGCTAnSXtNyvWYMK3YtV5jwudbq0T7nN9k4kmE4CBuwPqyJ+KBzepSTh0huivV2gLbSMEzTTmfeYw== caseless@~0.12.0: version "0.12.0" @@ -2127,7 +2129,7 @@ chai@^4.2.0: pathval "^1.1.0" type-detect "^4.0.5" -chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2165,9 +2167,9 @@ chokidar@3.3.0: fsevents "~2.1.1" "chokidar@>=2.0.0 <4.0.0": - version "3.4.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" - integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== + version "3.5.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.0.tgz#458a4816a415e9d3b3caa4faec2b96a6935a9e65" + integrity sha512-JgQM9JS92ZbFR4P90EvmzNpSGhpPBGBSj10PILeDyYFwp4h2/D9OM03wsJ4zW1fEp4ka2DGrnUeD7FuvQ2aZ2Q== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -2177,7 +2179,7 @@ chokidar@3.3.0: normalize-path "~3.0.0" readdirp "~3.5.0" optionalDependencies: - fsevents "~2.1.2" + fsevents "~2.3.1" chokidar@^2.1.8: version "2.1.8" @@ -2437,11 +2439,11 @@ copy-descriptor@^0.1.0: integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-js-compat@^3.8.0: - version "3.8.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.1.tgz#8d1ddd341d660ba6194cbe0ce60f4c794c87a36e" - integrity sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ== + version "3.8.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.2.tgz#3717f51f6c3d2ebba8cbf27619b57160029d1d4c" + integrity sha512-LO8uL9lOIyRRrQmZxHZFl1RV+ZbcsAkFWTktn5SmH40WgLtSNYN4m4W2v9ONT147PxBY/XrRhrWq8TlvObyUjQ== dependencies: - browserslist "^4.15.0" + browserslist "^4.16.0" semver "7.0.0" core-js@^2.4.0: @@ -2450,9 +2452,9 @@ core-js@^2.4.0: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.0.0: - version "3.8.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.1.tgz#f51523668ac8a294d1285c3b9db44025fda66d47" - integrity sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg== + version "3.8.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.2.tgz#0a1fd6709246da9ca8eff5bb0cbd15fba9ac7044" + integrity sha512-FfApuSRgrR6G5s58casCBd9M2k+4ikuu4wbW6pJyYU7bd9zvFc9qf7vr5xmrZOhT9nn+8uwlH1oRR9jTnFoA3A== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -2537,9 +2539,9 @@ css-loader@^5.0.1: semver "^7.3.2" css-minimizer-webpack-plugin@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-1.1.5.tgz#f6f41358518d0f28b7a2d6819dfe1e410bc404f6" - integrity sha512-mXgaoFjNpIudZfxD49N1aPtLxfXGJt+BVPVjQ+H66I48b5n4wJtFpYfffVr7izK8W6fD01J7K0kUcP6HGjw90w== + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-1.2.0.tgz#3e9d75f6bcc16f1eb84d56ebfee124d1e1f2e1c5" + integrity sha512-XU4+PXw7QKAlRGU+fB386YiczAAPtk0kVsB/Qf2nX8GJaOXgTsk/PST8YBExeoD299wheG//MCCKlCD5fykb7Q== dependencies: cacache "^15.0.5" cssnano "^4.1.10" @@ -2563,17 +2565,7 @@ css-select-base-adapter@^0.1.1: resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== -css-select@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-select@^2.0.0: +css-select@^2.0.0, css-select@^2.0.2: version "2.1.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== @@ -2599,11 +2591,6 @@ css-tree@^1.1.2: mdn-data "2.0.14" source-map "^0.6.1" -css-what@2.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" - integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== - css-what@^3.2.1: version "3.4.2" resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" @@ -2968,14 +2955,6 @@ domhandler@^2.3.0: dependencies: domelementtype "1" -domutils@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= - dependencies: - dom-serializer "0" - domelementtype "1" - domutils@^1.5.1, domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" @@ -3014,10 +2993,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.621: - version "1.3.633" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.633.tgz#16dd5aec9de03894e8d14a1db4cda8a369b9b7fe" - integrity sha512-bsVCsONiVX1abkWdH7KtpuDAhsQ3N3bjPYhROSAXE78roJKet0Y5wznA14JE9pzbwSZmSMAW6KiKYf1RvbTJkA== +electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.634: + version "1.3.635" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.635.tgz#8d1591eeca6b257d380061a2c04f0b3cc6c9e33b" + integrity sha512-RRriZOLs9CpW6KTLmgBqyUdnY0QNqqWs0HOtuQGGEMizOTNNn1P7sGRBxARnUeLejOsgwjDyRqT3E/CSst02ZQ== emoji-regex@^7.0.1: version "7.0.3" @@ -3322,9 +3301,9 @@ eslint-visitor-keys@^2.0.0: integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== "eslint@^6.0.0 || ^7.0.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092" - integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw== + version "7.17.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.17.0.tgz#4ccda5bf12572ad3bf760e6f195886f50569adb0" + integrity sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ== dependencies: "@babel/code-frame" "^7.0.0" "@eslint/eslintrc" "^0.2.2" @@ -3814,11 +3793,16 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fsevents@~2.1.1, fsevents@~2.1.2: +fsevents@~2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +fsevents@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.1.tgz#b209ab14c61012636c8863507edf7fb68cc54e9f" + integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -3851,7 +3835,7 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= -get-intrinsic@^1.0.0, get-intrinsic@^1.0.1: +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49" integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg== @@ -4126,7 +4110,7 @@ html-tags@^2.0.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= -htmlparser2@^3.3.0: +htmlparser2@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -4176,9 +4160,9 @@ http-errors@~1.7.2: toidentifier "1.0.0" http-parser-js@>=0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77" - integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ== + version "0.5.3" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" + integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== http-proxy-middleware@0.19.1: version "0.19.1" @@ -4705,7 +4689,7 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -jest-worker@^26.3.0, jest-worker@^26.5.0, jest-worker@^26.6.1: +jest-worker@^26.3.0, jest-worker@^26.5.0, jest-worker@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== @@ -4797,6 +4781,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -4963,10 +4952,10 @@ load-json-file@^2.0.0: pify "^2.0.0" strip-bom "^3.0.0" -loader-runner@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.1.0.tgz#f70bc0c29edbabdf2043e7ee73ccc3fe1c96b42d" - integrity sha512-oR4lB4WvwFoC70ocraKhn5nkKSs23t57h9udUgw8o0iH8hMXeEoRuUgfcvgUwAJ1ZpRqBvcou4N2SMvM1DwMrA== +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== loader-utils@1.0.x: version "1.0.4" @@ -5226,22 +5215,17 @@ micromatch@^4.0.0: braces "^3.0.1" picomatch "^2.0.5" -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== - -"mime-db@>= 1.43.0 < 2": +mime-db@1.45.0, "mime-db@>= 1.43.0 < 2": version "1.45.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + version "2.1.28" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd" + integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ== dependencies: - mime-db "1.44.0" + mime-db "1.45.0" mime@1.6.0, mime@^1.4.1, mime@^1.6.0: version "1.6.0" @@ -5496,10 +5480,10 @@ node-notifier@^8.0.0: uuid "^8.3.0" which "^2.0.2" -node-releases@^1.1.67: - version "1.1.67" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12" - integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg== +node-releases@^1.1.69: + version "1.1.69" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.69.tgz#3149dbde53b781610cd8b486d62d86e26c3725f6" + integrity sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA== normalize-package-data@^2.3.2: version "2.5.0" @@ -5547,7 +5531,7 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -nth-check@^1.0.2, nth-check@~1.0.1: +nth-check@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== @@ -5752,7 +5736,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -6409,9 +6393,9 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.27, postcss@^7.0.3 supports-color "^6.1.0" postcss@^8.1.4: - version "8.2.2" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.2.tgz#60613b62297005084fd21024a68637798864fe26" - integrity sha512-HM1NDNWLgglJPQQMNwvLxgH2KcrKZklKLi/xXYIOaqQB57p/pDWEJNS83PVICYsn1Dg/9C26TiejNr422/ePaQ== + version "8.2.4" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.4.tgz#20a98a39cf303d15129c2865a9ec37eda0031d04" + integrity sha512-kRFftRoExRVXZlwUuay9iC824qmXPcQQVzAjbCCgjpXnkdMCJYBu2gTwAaFBzv8ewND6O8xFb3aELmEkh9zTzg== dependencies: colorette "^1.2.1" nanoid "^3.1.20" @@ -6759,13 +6743,13 @@ remove-trailing-separator@^1.0.1: integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= renderkid@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.4.tgz#d325e532afb28d3f8796ffee306be8ffd6fc864c" - integrity sha512-K2eXrSOJdq+HuKzlcjOlGoOarUu5SDguDEhE7+Ah4zuOWL40j8A/oHvLlLob9PSTNvVnBd+/q0Er1QfpEuem5g== + version "2.0.5" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.5.tgz#483b1ac59c6601ab30a7a596a5965cabccfdd0a5" + integrity sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ== dependencies: - css-select "^1.1.0" + css-select "^2.0.2" dom-converter "^0.2" - htmlparser2 "^3.3.0" + htmlparser2 "^3.10.1" lodash "^4.17.20" strip-ansi "^3.0.0" @@ -6826,6 +6810,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -6975,9 +6964,9 @@ safe-regex@^1.1.0: semver "^7.3.2" sass@^1.17.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.0.tgz#10101a026c13080b14e2b374d4e15ee24400a4d3" - integrity sha512-fhyqEbMIycQA4blrz/C0pYhv2o4x2y6FYYAH0CshBw3DXh5D5wyERgxw0ptdau1orc/GhNrhF7DFN2etyOCEng== + version "1.32.2" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.2.tgz#66dc0250bc86c15d19ddee7135e93d0cf3d3257b" + integrity sha512-u1pUuzqwz3SAgvHSWp1k0mRhX82b2DdlVnP6UIetQPZtYbuJUDaPQhZE12jyjB7vYeOScfz9WPsZJB6Rpk7heA== dependencies: chokidar ">=2.0.0 <4.0.0" @@ -7045,7 +7034,7 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2: +semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: version "7.3.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== @@ -7173,13 +7162,12 @@ simple-swizzle@^0.2.2: is-arrayish "^0.3.1" sinon@^9.0.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.2.tgz#b83cf5d43838f99cfa3644453f4c7db23e7bd535" - integrity sha512-9Owi+RisvCZpB0bdOVFfL314I6I4YoRlz6Isi4+fr8q8YQsDPoCe5UnmNtKHRThX3negz2bXHWIuiPa42vM8EQ== + version "9.2.3" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.3.tgz#f68ce414e843e2fd638703043c97f260697caa52" + integrity sha512-m+DyAWvqVHZtjnjX/nuShasykFeiZ+nPuEfD4G3gpvKGkXRhkF/6NSt2qN2FjZhfrcHXFzUzI+NLnk+42fnLEw== dependencies: "@sinonjs/commons" "^1.8.1" "@sinonjs/fake-timers" "^6.0.1" - "@sinonjs/formatio" "^5.0.1" "@sinonjs/samsam" "^5.3.0" diff "^4.0.2" nise "^4.0.4" @@ -7630,11 +7618,11 @@ symbol-tree@^3.2.2: integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== table@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/table/-/table-6.0.4.tgz#c523dd182177e926c723eb20e1b341238188aa0d" - integrity sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw== + version "6.0.7" + resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" + integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== dependencies: - ajv "^6.12.4" + ajv "^7.0.2" lodash "^4.17.20" slice-ansi "^4.0.0" string-width "^4.2.0" @@ -7650,9 +7638,9 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== tar@^6.0.2: - version "6.0.5" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" - integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== + version "6.1.0" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" + integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -7677,18 +7665,18 @@ terser-webpack-plugin@^4.2.3: webpack-sources "^1.4.3" terser-webpack-plugin@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.0.3.tgz#ec60542db2421f45735c719d2e17dabfbb2e3e42" - integrity sha512-zFdGk8Lh9ZJGPxxPE6jwysOlATWB8GMW8HcfGULWA/nPal+3VdATflQvSBSLQJRCmYZnfFJl6vkRTiwJGNgPiQ== + version "5.1.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz#7effadee06f7ecfa093dbbd3e9ab23f5f3ed8673" + integrity sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q== dependencies: - jest-worker "^26.6.1" - p-limit "^3.0.2" + jest-worker "^26.6.2" + p-limit "^3.1.0" schema-utils "^3.0.0" serialize-javascript "^5.0.1" source-map "^0.6.1" - terser "^5.3.8" + terser "^5.5.1" -terser@^5.3.4, terser@^5.3.8: +terser@^5.3.4, terser@^5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289" integrity sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ== @@ -7777,15 +7765,15 @@ tr46@^1.0.1: punycode "^2.1.0" ts-loader@^8.0.1: - version "8.0.13" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.13.tgz#2bebeb833570ca46bb9338322a9a29900e988535" - integrity sha512-1o1nO6aqouA23d2nlcMSEyPMAWRhnYUU0EQUJSc60E0TUyBNX792RHFYUN1ZM29vhMUNayrsbj2UVdZwKhXCDA== + version "8.0.14" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.14.tgz#e46ac1f8dcb88808d0b1335d2eae65b74bd78fe8" + integrity sha512-Jt/hHlUnApOZjnSjTmZ+AbD5BGlQFx3f1D0nYuNKwz0JJnuDGHJas6az+FlWKwwRTu+26GXpv249A8UAnYUpqA== dependencies: - chalk "^2.3.0" + chalk "^4.1.0" enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" + loader-utils "^2.0.0" micromatch "^4.0.0" - semver "^6.0.0" + semver "^7.3.4" tsconfig-paths@^3.9.0: version "3.9.0" @@ -7862,9 +7850,9 @@ typescript@>=3.6.3: integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== uglify-js@^3.1.4: - version "3.12.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.3.tgz#bb26c4abe0e68c55e9776bca9bed99a4df73facf" - integrity sha512-feZzR+kIcSVuLi3s/0x0b2Tx4Iokwqt+8PJM7yRHKuldg4MLdam4TCFeICv+lgDtuYiCtdmrtIP+uN9LWvDasw== + version "3.12.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.4.tgz#93de48bb76bb3ec0fc36563f871ba46e2ee5c7ee" + integrity sha512-L5i5jg/SHkEqzN18gQMTWsZk3KelRsfD1wUVNqtq0kzqWQqcJjyL8yc1o8hJgRrWqrAl2mUFbhfznEIoi7zi2A== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" @@ -7969,9 +7957,9 @@ upath@^1.1.1: integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== uri-js@^4.2.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" - integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" @@ -7985,15 +7973,6 @@ url-join@^2.0.5: resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= -url-loader@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" - integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== - dependencies: - loader-utils "^2.0.0" - mime-types "^2.1.27" - schema-utils "^3.0.0" - url-parse@^1.4.3, url-parse@^1.4.7: version "1.4.7" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" @@ -8265,10 +8244,10 @@ webpack-virtual-modules@^0.3.2: dependencies: debug "^3.0.0" -webpack@^5: - version "5.11.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.11.1.tgz#39b2b9daeb5c6c620e03b7556ec674eaed4016b4" - integrity sha512-tNUIdAmYJv+nupRs/U/gqmADm6fgrf5xE+rSlSsf2PgsGO7j2WG7ccU6AWNlOJlHFl+HnmXlBmHIkiLf+XA9mQ== +webpack@^5.12: + version "5.12.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.12.2.tgz#f79574cdb7a4ef711c5f47f3d189e045a14217e5" + integrity sha512-HiTXBGLFQiRecP5Fwrh21aaxlEUqQdDeUaninKVKX0Dtqaf+WjKCsNcv+UVftfYXrY0bnRQHnouw1x+CPqQKFQ== dependencies: "@types/eslint-scope" "^3.7.0" "@types/estree" "^0.0.45" @@ -8285,7 +8264,7 @@ webpack@^5: glob-to-regexp "^0.4.1" graceful-fs "^4.2.4" json-parse-better-errors "^1.0.2" - loader-runner "^4.1.0" + loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" pkg-dir "^5.0.0"