├── test ├── fixtures │ ├── entry.js │ ├── empty.json │ ├── broken-json-syntax.json │ ├── test │ │ ├── foo-0.json │ │ ├── foo-1.json │ │ ├── foo-2.json │ │ ├── foo-3.json │ │ └── foo-4.json │ ├── cache.js │ ├── include-exclude │ │ ├── exclude-1.json │ │ ├── exclude-2.json │ │ ├── include-1.json │ │ ├── include-2.json │ │ ├── include-3.json │ │ └── include-4.json │ ├── array.json │ ├── simple.json │ └── cache │ │ ├── cache-1.json │ │ ├── cache-2.json │ │ ├── cache-3.json │ │ ├── cache-4.json │ │ └── cache.json ├── helpers │ ├── getErrors.js │ ├── getWarnings.js │ ├── normalizedSourceMap.js │ ├── compile.js │ ├── ModifyExistingAsset.js │ ├── index.js │ ├── readAsset.js │ ├── readAssets.js │ ├── normalizeErrors.js │ ├── EmitNewAsset.js │ ├── emitAssetInChildCompilationLoader.js │ └── getCompiler.js ├── test-option.test.js ├── exclude-option.test.js ├── include-option.test.js ├── jsonMinimizerOptions-option.test.js ├── __snapshots__ │ ├── jsonMinimizerOptions-option.test.js.snap │ ├── test-option.test.js.snap │ ├── exclude-option.test.js.snap │ ├── include-option.test.js.snap │ ├── validate-options.test.js.snap │ └── JsonMinimizerPlugin.test.js.snap ├── validate-options.test.js └── JsonMinimizerPlugin.test.js ├── jest.config.js ├── .prettierignore ├── .gitattributes ├── .husky ├── pre-commit └── commit-msg ├── lint-staged.config.js ├── commitlint.config.js ├── eslint.config.mjs ├── .editorconfig ├── .gitignore ├── .cspell.json ├── babel.config.js ├── .github └── workflows │ ├── dependency-review.yml │ └── nodejs.yml ├── tsconfig.json ├── types ├── minify.d.ts └── index.d.ts ├── src ├── minify.js ├── options.json └── index.js ├── LICENSE ├── CHANGELOG.md ├── package.json └── README.md /test/fixtures/entry.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/empty.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: "node", 3 | }; 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /dist 3 | /node_modules 4 | /test/fixtures 5 | CHANGELOG.md -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | bin/* eol=lf 3 | yarn.lock -diff 4 | package-lock.json -diff -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install lint-staged 5 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit $1 5 | -------------------------------------------------------------------------------- /test/helpers/getErrors.js: -------------------------------------------------------------------------------- 1 | import normalizeErrors from "./normalizeErrors"; 2 | 3 | export default (stats) => normalizeErrors(stats.compilation.errors).sort(); 4 | -------------------------------------------------------------------------------- /test/helpers/getWarnings.js: -------------------------------------------------------------------------------- 1 | import normalizeErrors from "./normalizeErrors"; 2 | 3 | export default (stats) => normalizeErrors(stats.compilation.warnings).sort(); 4 | -------------------------------------------------------------------------------- /test/fixtures/broken-json-syntax.json: -------------------------------------------------------------------------------- 1 | { 2 | squadName: "Super hero squad", 3 | homeTown: "Metro City", 4 | formed: 2016, 5 | secretBase: "Super tower", 6 | active: true, 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/test/foo-0.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/test/foo-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/test/foo-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/test/foo-3.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/test/foo-4.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/cache.js: -------------------------------------------------------------------------------- 1 | import './cache/cache.json'; 2 | import './cache/cache-1.json'; 3 | import './cache/cache-2.json'; 4 | import './cache/cache-3.json'; 5 | import './cache/cache-4.json'; 6 | -------------------------------------------------------------------------------- /test/fixtures/include-exclude/exclude-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/include-exclude/exclude-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/include-exclude/include-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/include-exclude/include-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/include-exclude/include-3.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/include-exclude/include-4.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true 7 | } 8 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "*": [ 3 | "prettier --cache --write --ignore-unknown", 4 | "cspell --cache --no-must-find-files", 5 | ], 6 | "*.js": ["eslint --cache --fix"], 7 | }; 8 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@commitlint/config-conventional"], 3 | rules: { 4 | "header-max-length": [0], 5 | "body-max-line-length": [0], 6 | "footer-max-line-length": [0], 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "eslint/config"; 2 | import configs from "eslint-config-webpack/configs.js"; 3 | 4 | export default defineConfig([ 5 | { 6 | extends: [configs["recommended-dirty"]], 7 | }, 8 | ]); 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .vscode 4 | logs 5 | *.log 6 | npm-debug.log* 7 | .eslintcache 8 | .cspellcache 9 | /coverage 10 | /dist 11 | /local 12 | /reports 13 | /node_modules 14 | /test/outputs/ 15 | .DS_Store 16 | Thumbs.db 17 | .idea 18 | *.iml 19 | *.sublime-project 20 | *.sublime-workspace 21 | -------------------------------------------------------------------------------- /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "language": "en,en-gb", 4 | "words": ["memfs", "pathinfo", "commitlint", "nodenext", "eslintcache"], 5 | "ignorePaths": [ 6 | "CHANGELOG.md", 7 | "package.json", 8 | "dist/**", 9 | "**/__snapshots__/**", 10 | "package-lock.json", 11 | "node_modules", 12 | "coverage", 13 | "*.log" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const MIN_BABEL_VERSION = 7; 2 | 3 | module.exports = (api) => { 4 | api.assertVersion(MIN_BABEL_VERSION); 5 | api.cache(true); 6 | 7 | return { 8 | presets: [ 9 | [ 10 | "@babel/preset-env", 11 | { 12 | targets: { 13 | node: "18.12.0", 14 | }, 15 | }, 16 | ], 17 | ], 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: "Dependency Review" 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | dependency-review: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: "Checkout Repository" 12 | uses: actions/checkout@v5 13 | - name: "Dependency Review" 14 | uses: actions/dependency-review-action@v4 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | // "module": "nodenext", 5 | "moduleResolution": "node", 6 | "allowJs": true, 7 | "checkJs": true, 8 | "strict": true, 9 | "types": ["node"], 10 | "resolveJsonModule": true, 11 | "newLine": "LF", 12 | "allowSyntheticDefaultImports": true 13 | }, 14 | "include": ["./src/**/*"] 15 | } 16 | -------------------------------------------------------------------------------- /test/helpers/normalizedSourceMap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Normalize source map for testing purposes 3 | * @param {string} map The source map string to normalize 4 | * @returns {string} Normalized source map string 5 | */ 6 | export default function normalizedSourceMap(map) { 7 | return map.replace( 8 | // eslint-disable-next-line no-useless-escape 9 | /"sources":\[([\d\w\/\:\"\'].*)\]\,\"names\"/i, 10 | '"sources": [replaced for tests], "names"', 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /test/helpers/compile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compile webpack and return a promise with stats 3 | * @param {import('webpack').Compiler} compiler The webpack compiler instance 4 | * @returns {Promise} Promise that resolves with compilation stats 5 | */ 6 | export default function compile(compiler) { 7 | return new Promise((resolve, reject) => { 8 | compiler.run((err, stats) => { 9 | if (err) return reject(err); 10 | return resolve(stats); 11 | }); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /types/minify.d.ts: -------------------------------------------------------------------------------- 1 | export type InternalOptions = import("./index.js").InternalOptions; 2 | export type JSONOptions = import("./index.js").JSONOptions; 3 | export type MinimizedResult = import("./index.js").MinimizedResult; 4 | /** 5 | * Minify JSON content with specified options 6 | * @param {InternalOptions} options The options containing input and minimizer options 7 | * @returns {Promise} Promise that resolves with minimized JSON result 8 | */ 9 | export function minify(options: InternalOptions): Promise; 10 | -------------------------------------------------------------------------------- /test/helpers/ModifyExistingAsset.js: -------------------------------------------------------------------------------- 1 | export default class ExistingCommentsFile { 2 | constructor(options = {}) { 3 | this.options = options; 4 | } 5 | 6 | apply(compiler) { 7 | const plugin = { name: this.constructor.name }; 8 | const { RawSource } = compiler.webpack.sources; 9 | 10 | compiler.hooks.thisCompilation.tap(plugin, (compilation) => { 11 | compilation.hooks.additionalAssets.tap(plugin, () => { 12 | compilation.assets[this.options.name] = new RawSource( 13 | JSON.stringify({ modified: true }), 14 | ); 15 | }); 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/helpers/index.js: -------------------------------------------------------------------------------- 1 | export { default as EmitNewAsset } from "./EmitNewAsset"; 2 | export { default as compile } from "./compile"; 3 | export { default as ModifyExistingAsset } from "./ModifyExistingAsset"; 4 | export { default as getCompiler } from "./getCompiler"; 5 | export { default as getErrors } from "./getErrors"; 6 | export { default as normalizeErrors } from "./normalizeErrors"; 7 | export { default as getWarnings } from "./getWarnings"; 8 | export { default as readAsset } from "./readAsset"; 9 | export { default as normalizedSourceMap } from "./normalizedSourceMap"; 10 | export { default as readAssets } from "./readAssets"; 11 | -------------------------------------------------------------------------------- /test/helpers/readAsset.js: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | 3 | export default (asset, compiler, stats) => { 4 | const usedFs = compiler.outputFileSystem; 5 | const outputPath = stats.compilation.outputOptions.path; 6 | 7 | let data = ""; 8 | let targetFile = asset; 9 | 10 | const queryStringIdx = targetFile.indexOf("?"); 11 | 12 | if (queryStringIdx >= 0) { 13 | targetFile = targetFile.slice(0, queryStringIdx); 14 | } 15 | 16 | try { 17 | data = usedFs.readFileSync(path.join(outputPath, targetFile)).toString(); 18 | } catch (error) { 19 | data = error.toString(); 20 | } 21 | 22 | return data; 23 | }; 24 | -------------------------------------------------------------------------------- /test/helpers/readAssets.js: -------------------------------------------------------------------------------- 1 | import readAsset from "./readAsset"; 2 | 3 | /** 4 | * Read assets from webpack compilation stats 5 | * @param {import('webpack').Compiler} compiler The webpack compiler instance 6 | * @param {import('webpack').Stats} stats The webpack compilation stats 7 | * @param {RegExp} extRegexp Regular expression to filter assets by extension 8 | * @returns {{[key: string]: string}} Object containing filtered assets 9 | */ 10 | export default function readAssets(compiler, stats, extRegexp) { 11 | const assets = {}; 12 | 13 | for (const asset of Object.keys(stats.compilation.assets)) { 14 | if (extRegexp && extRegexp.test(asset)) { 15 | assets[asset] = readAsset(asset, compiler, stats); 16 | } 17 | } 18 | 19 | return assets; 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/array.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Molecule Man", 4 | "age": 29, 5 | "secretIdentity": "Dan Jukes", 6 | "powers": [ 7 | "Radiation resistance", 8 | "Turning tiny", 9 | "Radiation blast" 10 | ] 11 | }, 12 | { 13 | "name": "Madame Uppercut", 14 | "age": 39, 15 | "secretIdentity": "Jane Wilson", 16 | "powers": [ 17 | "Million tonne punch", 18 | "Damage resistance", 19 | "Superhuman reflexes" 20 | ] 21 | }, 22 | { 23 | "name": "Eternal Flame", 24 | "age": 1000000, 25 | "secretIdentity": "Unknown", 26 | "powers": [ 27 | "Immortality", 28 | "Heat Immunity", 29 | "Inferno", 30 | "Teleportation", 31 | "Interdimensional travel" 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /test/helpers/normalizeErrors.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Remove current working directory from error messages 3 | * @param {string} str The string to process 4 | * @returns {string} String with CWD removed 5 | */ 6 | function removeCWD(str) { 7 | const isWin = process.platform === "win32"; 8 | let cwd = process.cwd(); 9 | 10 | if (isWin) { 11 | str = str.replaceAll("\\", "/"); 12 | 13 | cwd = cwd.replaceAll("\\", "/"); 14 | } 15 | 16 | return str.replaceAll(new RegExp(cwd, "g"), ""); 17 | } 18 | 19 | /** 20 | * Normalize error messages by removing CWD and limiting to first two lines 21 | * @param {Array} errors Array of error objects 22 | * @returns {Array} Array of normalized error strings 23 | */ 24 | export default (errors) => 25 | errors.map((error) => 26 | removeCWD(error.toString().split("\n").slice(0, 2).join("\n")), 27 | ); 28 | -------------------------------------------------------------------------------- /test/helpers/EmitNewAsset.js: -------------------------------------------------------------------------------- 1 | export default class EmitNewAsset { 2 | constructor(options = {}) { 3 | this.options = options; 4 | } 5 | 6 | apply(compiler) { 7 | const pluginName = this.constructor.name; 8 | 9 | const { RawSource } = compiler.webpack.sources; 10 | 11 | compiler.hooks.compilation.tap(pluginName, (compilation) => { 12 | compilation.hooks.processAssets.tap( 13 | { 14 | name: pluginName, 15 | stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT, 16 | }, 17 | () => { 18 | compilation.emitAsset( 19 | this.options.name, 20 | new RawSource(` 21 | { 22 | "squadName": "Super hero squad", 23 | "homeTown": "Metro City", 24 | "formed": 2016, 25 | "secretBase": "Super tower", 26 | "active": true 27 | } 28 | `), 29 | ); 30 | }, 31 | ); 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/minify.js: -------------------------------------------------------------------------------- 1 | /** @typedef {import("./index.js").InternalOptions} InternalOptions */ 2 | /** @typedef {import("./index.js").JSONOptions} JSONOptions */ 3 | /** @typedef {import("./index.js").MinimizedResult} MinimizedResult */ 4 | 5 | const defaultMinimizerOptions = { 6 | replacer: undefined, 7 | 8 | space: undefined, 9 | }; 10 | 11 | /** 12 | * Minify JSON content with specified options 13 | * @param {InternalOptions} options The options containing input and minimizer options 14 | * @returns {Promise} Promise that resolves with minimized JSON result 15 | */ 16 | const minify = async (options) => { 17 | const { input, minimizerOptions } = options; 18 | const { replacer, space } = { 19 | ...defaultMinimizerOptions, 20 | ...minimizerOptions, 21 | }; 22 | 23 | const result = JSON.stringify(JSON.parse(input), replacer, space); 24 | 25 | return { code: result }; 26 | }; 27 | 28 | module.exports = { minify }; 29 | -------------------------------------------------------------------------------- /test/fixtures/simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true, 7 | "members": [ 8 | { 9 | "name": "Molecule Man", 10 | "age": 29, 11 | "secretIdentity": "Dan Jukes", 12 | "powers": [ 13 | "Radiation resistance", 14 | "Turning tiny", 15 | "Radiation blast" 16 | ] 17 | }, 18 | { 19 | "name": "Madame Uppercut", 20 | "age": 39, 21 | "secretIdentity": "Jane Wilson", 22 | "powers": [ 23 | "Million tonne punch", 24 | "Damage resistance", 25 | "Superhuman reflexes" 26 | ] 27 | }, 28 | { 29 | "name": "Eternal Flame", 30 | "age": 1000000, 31 | "secretIdentity": "Unknown", 32 | "powers": [ 33 | "Immortality", 34 | "Heat Immunity", 35 | "Inferno", 36 | "Teleportation", 37 | "Interdimensional travel" 38 | ] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/cache/cache-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true, 7 | "members": [ 8 | { 9 | "name": "Molecule Man", 10 | "age": 29, 11 | "secretIdentity": "Dan Jukes", 12 | "powers": [ 13 | "Radiation resistance", 14 | "Turning tiny", 15 | "Radiation blast" 16 | ] 17 | }, 18 | { 19 | "name": "Madame Uppercut", 20 | "age": 39, 21 | "secretIdentity": "Jane Wilson", 22 | "powers": [ 23 | "Million tonne punch", 24 | "Damage resistance", 25 | "Superhuman reflexes" 26 | ] 27 | }, 28 | { 29 | "name": "Eternal Flame", 30 | "age": 1000000, 31 | "secretIdentity": "Unknown", 32 | "powers": [ 33 | "Immortality", 34 | "Heat Immunity", 35 | "Inferno", 36 | "Teleportation", 37 | "Interdimensional travel" 38 | ] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/cache/cache-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true, 7 | "members": [ 8 | { 9 | "name": "Molecule Man", 10 | "age": 29, 11 | "secretIdentity": "Dan Jukes", 12 | "powers": [ 13 | "Radiation resistance", 14 | "Turning tiny", 15 | "Radiation blast" 16 | ] 17 | }, 18 | { 19 | "name": "Madame Uppercut", 20 | "age": 39, 21 | "secretIdentity": "Jane Wilson", 22 | "powers": [ 23 | "Million tonne punch", 24 | "Damage resistance", 25 | "Superhuman reflexes" 26 | ] 27 | }, 28 | { 29 | "name": "Eternal Flame", 30 | "age": 1000000, 31 | "secretIdentity": "Unknown", 32 | "powers": [ 33 | "Immortality", 34 | "Heat Immunity", 35 | "Inferno", 36 | "Teleportation", 37 | "Interdimensional travel" 38 | ] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/cache/cache-3.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true, 7 | "members": [ 8 | { 9 | "name": "Molecule Man", 10 | "age": 29, 11 | "secretIdentity": "Dan Jukes", 12 | "powers": [ 13 | "Radiation resistance", 14 | "Turning tiny", 15 | "Radiation blast" 16 | ] 17 | }, 18 | { 19 | "name": "Madame Uppercut", 20 | "age": 39, 21 | "secretIdentity": "Jane Wilson", 22 | "powers": [ 23 | "Million tonne punch", 24 | "Damage resistance", 25 | "Superhuman reflexes" 26 | ] 27 | }, 28 | { 29 | "name": "Eternal Flame", 30 | "age": 1000000, 31 | "secretIdentity": "Unknown", 32 | "powers": [ 33 | "Immortality", 34 | "Heat Immunity", 35 | "Inferno", 36 | "Teleportation", 37 | "Interdimensional travel" 38 | ] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/cache/cache-4.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true, 7 | "members": [ 8 | { 9 | "name": "Molecule Man", 10 | "age": 29, 11 | "secretIdentity": "Dan Jukes", 12 | "powers": [ 13 | "Radiation resistance", 14 | "Turning tiny", 15 | "Radiation blast" 16 | ] 17 | }, 18 | { 19 | "name": "Madame Uppercut", 20 | "age": 39, 21 | "secretIdentity": "Jane Wilson", 22 | "powers": [ 23 | "Million tonne punch", 24 | "Damage resistance", 25 | "Superhuman reflexes" 26 | ] 27 | }, 28 | { 29 | "name": "Eternal Flame", 30 | "age": 1000000, 31 | "secretIdentity": "Unknown", 32 | "powers": [ 33 | "Immortality", 34 | "Heat Immunity", 35 | "Inferno", 36 | "Teleportation", 37 | "Interdimensional travel" 38 | ] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/cache/cache.json: -------------------------------------------------------------------------------- 1 | { 2 | "squadName": "Super hero squad", 3 | "homeTown": "Metro City", 4 | "formed": 2016, 5 | "secretBase": "Super tower", 6 | "active": true, 7 | "members": [ 8 | { 9 | "name": "Molecule Man", 10 | "age": 29, 11 | "secretIdentity": "Dan Jukes", 12 | "powers": [ 13 | "Radiation resistance", 14 | "Turning tiny", 15 | "Radiation blast" 16 | ] 17 | }, 18 | { 19 | "name": "Madame Uppercut", 20 | "age": 39, 21 | "secretIdentity": "Jane Wilson", 22 | "powers": [ 23 | "Million tonne punch", 24 | "Damage resistance", 25 | "Superhuman reflexes" 26 | ] 27 | }, 28 | { 29 | "name": "Eternal Flame", 30 | "age": 1000000, 31 | "secretIdentity": "Unknown", 32 | "powers": [ 33 | "Immortality", 34 | "Heat Immunity", 35 | "Inferno", 36 | "Teleportation", 37 | "Interdimensional travel" 38 | ] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | 'Software'), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /test/helpers/emitAssetInChildCompilationLoader.js: -------------------------------------------------------------------------------- 1 | class PreCopyPlugin { 2 | constructor(options = {}) { 3 | this.options = options.options || {}; 4 | } 5 | 6 | apply(compiler) { 7 | const plugin = { name: "PreCopyPlugin" }; 8 | const { RawSource } = compiler.webpack.sources; 9 | 10 | compiler.hooks.compilation.tap(plugin, (compilation) => { 11 | compilation.hooks.additionalAssets.tapAsync(plugin, (callback) => { 12 | compilation.emitAsset("simple.json", new RawSource('{"x": 5}')); 13 | 14 | callback(); 15 | }); 16 | }); 17 | } 18 | } 19 | 20 | /** 21 | * Webpack loader that creates a child compilation with asset emission 22 | * @returns {void} 23 | */ 24 | export default function loader() { 25 | const callback = this.async(); 26 | 27 | const childCompiler = this._compilation.createChildCompiler( 28 | "preloader", 29 | this.options, 30 | ); 31 | 32 | new PreCopyPlugin().apply(childCompiler); 33 | 34 | childCompiler.runAsChild((error) => { 35 | if (error) { 36 | return callback(error); 37 | } 38 | 39 | return callback(null, "export default 1"); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /test/test-option.test.js: -------------------------------------------------------------------------------- 1 | import JsonMinimizerPlugin from "../src/index"; 2 | 3 | import { 4 | compile, 5 | getCompiler, 6 | getErrors, 7 | getWarnings, 8 | readAssets, 9 | } from "./helpers"; 10 | 11 | describe('when applied with "test" option', () => { 12 | let compiler; 13 | 14 | beforeEach(() => { 15 | jest.clearAllMocks(); 16 | 17 | const testJsonId = "./test/foo-[0-4].json"; 18 | 19 | compiler = getCompiler(testJsonId); 20 | }); 21 | 22 | it("matches snapshot with empty value", async () => { 23 | new JsonMinimizerPlugin().apply(compiler); 24 | 25 | const stats = await compile(compiler); 26 | 27 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 28 | expect(getErrors(stats)).toMatchSnapshot("errors"); 29 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 30 | }); 31 | 32 | it('matches snapshot for a single "test" value (RegExp)', async () => { 33 | new JsonMinimizerPlugin({ 34 | test: /foo-[1-3]\.json/, 35 | }).apply(compiler); 36 | 37 | const stats = await compile(compiler); 38 | 39 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 40 | expect(getErrors(stats)).toMatchSnapshot("errors"); 41 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 42 | }); 43 | 44 | it('matches snapshot for multiple "test" value (RegExp)', async () => { 45 | new JsonMinimizerPlugin({ 46 | test: [/foo-[0]\.json/, /foo-[1-2]\.json/], 47 | }).apply(compiler); 48 | 49 | const stats = await compile(compiler); 50 | 51 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 52 | expect(getErrors(stats)).toMatchSnapshot("errors"); 53 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /test/exclude-option.test.js: -------------------------------------------------------------------------------- 1 | import JsonMinimizerPlugin from "../src/index"; 2 | 3 | import { 4 | compile, 5 | getCompiler, 6 | getErrors, 7 | getWarnings, 8 | readAssets, 9 | } from "./helpers"; 10 | 11 | describe("exclude option", () => { 12 | let compiler; 13 | 14 | beforeEach(() => { 15 | const testJsonId = "./include-exclude/*.json"; 16 | 17 | compiler = getCompiler(testJsonId); 18 | }); 19 | 20 | it("should match snapshot for a single RegExp value exclude", async () => { 21 | new JsonMinimizerPlugin({ 22 | exclude: /include-exclude\/exclude/i, 23 | }).apply(compiler); 24 | 25 | const stats = await compile(compiler); 26 | 27 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 28 | expect(getErrors(stats)).toMatchSnapshot("errors"); 29 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 30 | }); 31 | 32 | it("should match snapshot for multiple RegExp values exclude", async () => { 33 | new JsonMinimizerPlugin({ 34 | exclude: [ 35 | /include-exclude\/exclude-(1)/i, 36 | /include-exclude\/exclude-(2)/i, 37 | ], 38 | }).apply(compiler); 39 | 40 | const stats = await compile(compiler); 41 | 42 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 43 | expect(getErrors(stats)).toMatchSnapshot("errors"); 44 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 45 | }); 46 | 47 | it("should match snapshot for multiple String values exclude", async () => { 48 | new JsonMinimizerPlugin({ 49 | exclude: ["include-exclude/exclude-1", "include-exclude/exclude-2"], 50 | }).apply(compiler); 51 | 52 | const stats = await compile(compiler); 53 | 54 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 55 | expect(getErrors(stats)).toMatchSnapshot("errors"); 56 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/include-option.test.js: -------------------------------------------------------------------------------- 1 | import JsonMinimizerPlugin from "../src/index"; 2 | 3 | import { 4 | compile, 5 | getCompiler, 6 | getErrors, 7 | getWarnings, 8 | readAssets, 9 | } from "./helpers"; 10 | 11 | describe("include option", () => { 12 | let compiler; 13 | 14 | beforeEach(() => { 15 | const testJsonId = "./include-exclude/*.json"; 16 | 17 | compiler = getCompiler(testJsonId); 18 | }); 19 | 20 | it("should match snapshot for a single RegExp value include", async () => { 21 | new JsonMinimizerPlugin({ 22 | include: /include-exclude\/include/i, 23 | }).apply(compiler); 24 | 25 | const stats = await compile(compiler); 26 | 27 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 28 | expect(getErrors(stats)).toMatchSnapshot("errors"); 29 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 30 | }); 31 | 32 | it("should match snapshot for multiple RegExp values include", async () => { 33 | new JsonMinimizerPlugin({ 34 | include: [ 35 | /include-exclude\/include-(1|2)/i, 36 | /include-exclude\/include-(3|4)/i, 37 | ], 38 | }).apply(compiler); 39 | 40 | const stats = await compile(compiler); 41 | 42 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 43 | expect(getErrors(stats)).toMatchSnapshot("errors"); 44 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 45 | }); 46 | 47 | it("should match snapshot for multiple String values include", async () => { 48 | new JsonMinimizerPlugin({ 49 | exclude: [ 50 | "include-exclude/include-1", 51 | "include-exclude/include-2", 52 | "include-exclude/include-3", 53 | "include-exclude/include-4", 54 | ], 55 | }).apply(compiler); 56 | 57 | const stats = await compile(compiler); 58 | 59 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 60 | expect(getErrors(stats)).toMatchSnapshot("errors"); 61 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/jsonMinimizerOptions-option.test.js: -------------------------------------------------------------------------------- 1 | import JsonMinimizerPlugin from "../src/index"; 2 | 3 | import { 4 | compile, 5 | getCompiler, 6 | getErrors, 7 | getWarnings, 8 | readAssets, 9 | } from "./helpers"; 10 | 11 | describe('when applied with "minimizerOptions" option', () => { 12 | it('should work "space" options', async () => { 13 | const testHtmlId = "./simple.json"; 14 | const compiler = getCompiler(testHtmlId); 15 | 16 | new JsonMinimizerPlugin({ 17 | minimizerOptions: { 18 | space: 2, 19 | }, 20 | }).apply(compiler); 21 | 22 | const stats = await compile(compiler); 23 | 24 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 25 | expect(getErrors(stats)).toMatchSnapshot("errors"); 26 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 27 | }); 28 | 29 | it('should work "replacer" options', async () => { 30 | const testHtmlId = "./simple.json"; 31 | const compiler = getCompiler(testHtmlId); 32 | 33 | new JsonMinimizerPlugin({ 34 | minimizerOptions: { 35 | replacer: ["squadName", "homeTown"], 36 | }, 37 | }).apply(compiler); 38 | 39 | const stats = await compile(compiler); 40 | 41 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 42 | expect(getErrors(stats)).toMatchSnapshot("errors"); 43 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 44 | }); 45 | 46 | it('should work if "replacer" options is function', async () => { 47 | const testHtmlId = "./simple.json"; 48 | const compiler = getCompiler(testHtmlId); 49 | 50 | new JsonMinimizerPlugin({ 51 | minimizerOptions: { 52 | replacer: (key, value) => { 53 | if (Array.isArray(value)) { 54 | return undefined; 55 | } 56 | 57 | return value; 58 | }, 59 | }, 60 | }).apply(compiler); 61 | 62 | const stats = await compile(compiler); 63 | 64 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 65 | expect(getErrors(stats)).toMatchSnapshot("errors"); 66 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /test/helpers/getCompiler.js: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | 3 | import CopyPlugin from "copy-webpack-plugin"; 4 | import { Volume, createFsFromVolume } from "memfs"; 5 | import webpack from "webpack"; 6 | 7 | /** 8 | * Create a webpack compiler instance for testing 9 | * @param {string} jsonFixture Path to JSON fixture file 10 | * @param {object} config Additional webpack configuration 11 | * @returns {import('webpack').Compiler} Webpack compiler instance 12 | */ 13 | export default function getCompiler(jsonFixture, config = {}) { 14 | const compiler = webpack( 15 | Array.isArray(config) 16 | ? config 17 | : { 18 | mode: "production", 19 | bail: true, 20 | devtool: config.devtool || false, 21 | context: path.resolve(__dirname, "../fixtures"), 22 | entry: path.resolve(__dirname, "../fixtures/entry.js"), 23 | optimization: { 24 | minimize: false, 25 | }, 26 | output: { 27 | pathinfo: false, 28 | path: path.resolve(__dirname, "../dist"), 29 | filename: "[name].js", 30 | chunkFilename: "[id].[name].js", 31 | }, 32 | plugins: [ 33 | jsonFixture 34 | ? [ 35 | new CopyPlugin({ 36 | patterns: [ 37 | { 38 | context: path.resolve(__dirname, "..", "fixtures"), 39 | from: jsonFixture, 40 | }, 41 | ], 42 | }), 43 | ] 44 | : [], 45 | ].flat(), 46 | module: { 47 | rules: [ 48 | !jsonFixture 49 | ? [ 50 | { 51 | test: /\.json$/i, 52 | type: "asset/resource", 53 | generator: { 54 | filename: "[name][ext]", 55 | }, 56 | }, 57 | ] 58 | : [], 59 | ].flat(), 60 | }, 61 | ...config, 62 | }, 63 | ); 64 | 65 | if (!config.outputFileSystem) { 66 | compiler.outputFileSystem = createFsFromVolume(new Volume()); 67 | } 68 | 69 | return compiler; 70 | } 71 | 72 | getCompiler.isWebpack4 = () => webpack.version[0] === "4"; 73 | -------------------------------------------------------------------------------- /test/__snapshots__/jsonMinimizerOptions-option.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`when applied with "minimizerOptions" option should work "replacer" options: assets 1`] = ` 4 | { 5 | "simple.json": "{"squadName":"Super hero squad","homeTown":"Metro City"}", 6 | } 7 | `; 8 | 9 | exports[`when applied with "minimizerOptions" option should work "replacer" options: errors 1`] = `[]`; 10 | 11 | exports[`when applied with "minimizerOptions" option should work "replacer" options: warnings 1`] = `[]`; 12 | 13 | exports[`when applied with "minimizerOptions" option should work "space" options: assets 1`] = ` 14 | { 15 | "simple.json": "{ 16 | "squadName": "Super hero squad", 17 | "homeTown": "Metro City", 18 | "formed": 2016, 19 | "secretBase": "Super tower", 20 | "active": true, 21 | "members": [ 22 | { 23 | "name": "Molecule Man", 24 | "age": 29, 25 | "secretIdentity": "Dan Jukes", 26 | "powers": [ 27 | "Radiation resistance", 28 | "Turning tiny", 29 | "Radiation blast" 30 | ] 31 | }, 32 | { 33 | "name": "Madame Uppercut", 34 | "age": 39, 35 | "secretIdentity": "Jane Wilson", 36 | "powers": [ 37 | "Million tonne punch", 38 | "Damage resistance", 39 | "Superhuman reflexes" 40 | ] 41 | }, 42 | { 43 | "name": "Eternal Flame", 44 | "age": 1000000, 45 | "secretIdentity": "Unknown", 46 | "powers": [ 47 | "Immortality", 48 | "Heat Immunity", 49 | "Inferno", 50 | "Teleportation", 51 | "Interdimensional travel" 52 | ] 53 | } 54 | ] 55 | }", 56 | } 57 | `; 58 | 59 | exports[`when applied with "minimizerOptions" option should work "space" options: errors 1`] = `[]`; 60 | 61 | exports[`when applied with "minimizerOptions" option should work "space" options: warnings 1`] = `[]`; 62 | 63 | exports[`when applied with "minimizerOptions" option should work if "replacer" options is function: assets 1`] = ` 64 | { 65 | "simple.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 66 | } 67 | `; 68 | 69 | exports[`when applied with "minimizerOptions" option should work if "replacer" options is function: errors 1`] = `[]`; 70 | 71 | exports[`when applied with "minimizerOptions" option should work if "replacer" options is function: warnings 1`] = `[]`; 72 | -------------------------------------------------------------------------------- /src/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": { 3 | "Rule": { 4 | "description": "Filtering rule as regex or string.", 5 | "anyOf": [ 6 | { 7 | "instanceof": "RegExp", 8 | "tsType": "RegExp" 9 | }, 10 | { 11 | "type": "string", 12 | "minLength": 1 13 | } 14 | ] 15 | }, 16 | "Rules": { 17 | "description": "Filtering rules.", 18 | "anyOf": [ 19 | { 20 | "type": "array", 21 | "items": { 22 | "description": "A rule condition.", 23 | "oneOf": [ 24 | { 25 | "$ref": "#/definitions/Rule" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "$ref": "#/definitions/Rule" 32 | } 33 | ] 34 | }, 35 | "StringPattern": { 36 | "type": "string", 37 | "minLength": 1 38 | } 39 | }, 40 | "title": "JsonMinimizerWebpackPluginOptions", 41 | "type": "object", 42 | "properties": { 43 | "test": { 44 | "description": "Include all modules that pass test assertion.", 45 | "link": "https://github.com/webpack/json-minimizer-webpack-plugin#test", 46 | "oneOf": [ 47 | { 48 | "$ref": "#/definitions/Rules" 49 | } 50 | ] 51 | }, 52 | "include": { 53 | "description": "Include all modules matching any of these conditions.", 54 | "link": "https://github.com/webpack/json-minimizer-webpack-plugin#include", 55 | "oneOf": [ 56 | { 57 | "$ref": "#/definitions/Rules" 58 | } 59 | ] 60 | }, 61 | "exclude": { 62 | "description": "Exclude all modules matching any of these conditions.", 63 | "link": "https://github.com/webpack/json-minimizer-webpack-plugin#exclude", 64 | "oneOf": [ 65 | { 66 | "$ref": "#/definitions/Rules" 67 | } 68 | ] 69 | }, 70 | "minimizerOptions": { 71 | "description": "Options for `jsonMinimizerOptions`.", 72 | "link": "https://github.com/webpack/json-minimizer-webpack-plugin#minimizeroptions", 73 | "additionalProperties": false, 74 | "type": "object", 75 | "properties": { 76 | "replacer": { 77 | "anyOf": [ 78 | { 79 | "type": "null" 80 | }, 81 | { 82 | "instanceof": "Function" 83 | }, 84 | { 85 | "type": "array", 86 | "items": { 87 | "anyOf": [ 88 | { 89 | "$ref": "#/definitions/StringPattern" 90 | }, 91 | { 92 | "type": "number" 93 | } 94 | ] 95 | } 96 | } 97 | ] 98 | }, 99 | "space": { 100 | "anyOf": [ 101 | { 102 | "type": "null" 103 | }, 104 | { 105 | "$ref": "#/definitions/StringPattern" 106 | }, 107 | { 108 | "type": "number" 109 | } 110 | ] 111 | } 112 | } 113 | } 114 | }, 115 | "additionalProperties": false 116 | } 117 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: json-minimizer-webpack-plugin 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | pull_request: 9 | branches: 10 | - main 11 | - next 12 | 13 | permissions: 14 | contents: read 15 | 16 | jobs: 17 | lint: 18 | name: Lint - ${{ matrix.os }} - Node v${{ matrix.node-version }} 19 | 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | strategy: 24 | matrix: 25 | os: [ubuntu-latest] 26 | node-version: [lts/*] 27 | 28 | runs-on: ${{ matrix.os }} 29 | 30 | concurrency: 31 | group: lint-${{ matrix.os }}-v${{ matrix.node-version }}-${{ github.ref }} 32 | cancel-in-progress: true 33 | 34 | steps: 35 | - uses: actions/checkout@v5 36 | with: 37 | fetch-depth: 0 38 | 39 | - name: Use Node.js ${{ matrix.node-version }} 40 | uses: actions/setup-node@v4 41 | with: 42 | node-version: ${{ matrix.node-version }} 43 | cache: "npm" 44 | 45 | - name: Install dependencies 46 | run: npm ci 47 | 48 | - name: Lint 49 | run: npm run lint 50 | 51 | - name: Build types 52 | run: npm run build:types 53 | 54 | - name: Check types 55 | run: if [ -n "$(git status types --porcelain)" ]; then echo "Missing types. Update types by running 'npm run build:types'"; exit 1; else echo "All types are valid"; fi 56 | 57 | - name: Security audit 58 | run: npm run security 59 | 60 | - name: Validate PR commits with commitlint 61 | if: github.event_name == 'pull_request' 62 | run: npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose 63 | 64 | test: 65 | name: Test - ${{ matrix.os }} - Node v${{ matrix.node-version }}, Webpack ${{ matrix.webpack-version }} 66 | 67 | strategy: 68 | matrix: 69 | os: [ubuntu-latest, windows-latest, macos-latest] 70 | node-version: [18.x, 20.x, 22.x, 24.x] 71 | webpack-version: [latest] 72 | 73 | runs-on: ${{ matrix.os }} 74 | 75 | concurrency: 76 | group: test-${{ matrix.os }}-v${{ matrix.node-version }}-${{ matrix.webpack-version }}-${{ github.ref }} 77 | cancel-in-progress: true 78 | 79 | steps: 80 | - name: Setup Git 81 | if: matrix.os == 'windows-latest' 82 | run: git config --global core.autocrlf input 83 | 84 | - uses: actions/checkout@v5 85 | 86 | - name: Use Node.js ${{ matrix.node-version }} 87 | uses: actions/setup-node@v4 88 | with: 89 | node-version: ${{ matrix.node-version }} 90 | cache: "npm" 91 | 92 | - name: Install dependencies 93 | run: npm ci 94 | 95 | - name: Install webpack ${{ matrix.webpack-version }} 96 | if: matrix.webpack-version != 'latest' 97 | run: npm i webpack@${{ matrix.webpack-version }} 98 | 99 | - name: Run tests for webpack version ${{ matrix.webpack-version }} 100 | run: npm run test:coverage -- --ci 101 | 102 | - name: Submit coverage data to codecov 103 | uses: codecov/codecov-action@v5 104 | with: 105 | token: ${{ secrets.CODECOV_TOKEN }} 106 | -------------------------------------------------------------------------------- /test/__snapshots__/test-option.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`when applied with "test" option matches snapshot for a single "test" value (RegExp): assets 1`] = ` 4 | { 5 | "test/foo-0.json": "{ 6 | "squadName": "Super hero squad", 7 | "homeTown": "Metro City", 8 | "formed": 2016, 9 | "secretBase": "Super tower", 10 | "active": true 11 | } 12 | ", 13 | "test/foo-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 14 | "test/foo-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 15 | "test/foo-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 16 | "test/foo-4.json": "{ 17 | "squadName": "Super hero squad", 18 | "homeTown": "Metro City", 19 | "formed": 2016, 20 | "secretBase": "Super tower", 21 | "active": true 22 | } 23 | ", 24 | } 25 | `; 26 | 27 | exports[`when applied with "test" option matches snapshot for a single "test" value (RegExp): errors 1`] = `[]`; 28 | 29 | exports[`when applied with "test" option matches snapshot for a single "test" value (RegExp): warnings 1`] = `[]`; 30 | 31 | exports[`when applied with "test" option matches snapshot for multiple "test" value (RegExp): assets 1`] = ` 32 | { 33 | "test/foo-0.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 34 | "test/foo-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 35 | "test/foo-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 36 | "test/foo-3.json": "{ 37 | "squadName": "Super hero squad", 38 | "homeTown": "Metro City", 39 | "formed": 2016, 40 | "secretBase": "Super tower", 41 | "active": true 42 | } 43 | ", 44 | "test/foo-4.json": "{ 45 | "squadName": "Super hero squad", 46 | "homeTown": "Metro City", 47 | "formed": 2016, 48 | "secretBase": "Super tower", 49 | "active": true 50 | } 51 | ", 52 | } 53 | `; 54 | 55 | exports[`when applied with "test" option matches snapshot for multiple "test" value (RegExp): errors 1`] = `[]`; 56 | 57 | exports[`when applied with "test" option matches snapshot for multiple "test" value (RegExp): warnings 1`] = `[]`; 58 | 59 | exports[`when applied with "test" option matches snapshot with empty value: assets 1`] = ` 60 | { 61 | "test/foo-0.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 62 | "test/foo-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 63 | "test/foo-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 64 | "test/foo-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 65 | "test/foo-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 66 | } 67 | `; 68 | 69 | exports[`when applied with "test" option matches snapshot with empty value: errors 1`] = `[]`; 70 | 71 | exports[`when applied with "test" option matches snapshot with empty value: warnings 1`] = `[]`; 72 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [5.0.1](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v5.0.0...v5.0.1) (2025-04-07) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * types ([#112](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/issues/112)) ([04a60f6](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/commit/04a60f62efb5858d6b1230832030952eb26d73ee)) 11 | 12 | ## [5.0.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v4.0.0...v5.0.0) (2024-01-15) 13 | 14 | 15 | ### ⚠ BREAKING CHANGES 16 | 17 | * minimum supported Node.js version is `18.12.0` ([53b80b5](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/commit/53b80b5d5501c5b8cb60d12697de80a1ab25988b)) 18 | 19 | ## [4.0.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v3.3.0...v4.0.0) (2022-05-17) 20 | 21 | 22 | ### ⚠ BREAKING CHANGES 23 | 24 | * minimum supported `Node.js` version is `14.15.0` 25 | 26 | ## [3.3.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v3.2.0...v3.3.0) (2021-12-16) 27 | 28 | 29 | ### Features 30 | 31 | * removed cjs wrapper and generated types in commonjs format (`export =` and `namespaces` used in types), now you can directly use exported types ([#29](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/issues/29)) ([04140de](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/commit/04140de65cb471ea152dd67b5300f81239f34506)) 32 | 33 | ## [3.2.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v3.1.1...v3.2.0) (2021-12-06) 34 | 35 | 36 | ### Features 37 | 38 | * added types ([97c21b7](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/commit/97c21b7ab0ecab1454d034051f47b2e73582a3d7)) 39 | 40 | ### [3.1.1](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v3.1.0...v3.1.1) (2021-11-17) 41 | 42 | 43 | ### Chore 44 | 45 | * update `schema-utils` package to `4.0.0` version 46 | 47 | ## [3.1.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v3.0.0...v3.1.0) (2021-10-04) 48 | 49 | 50 | ### Features 51 | 52 | * better validation errors ([#25](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/issues/25)) ([4401c63](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/commit/4401c632b27dd894269ab96d65dab8b07597df42)) 53 | 54 | ## [3.0.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v2.1.0...v3.0.0) (2021-05-18) 55 | 56 | 57 | ### ⚠ BREAKING CHANGES 58 | 59 | * minimum supported `Node.js` version is `12.13.0` 60 | 61 | ## [2.1.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v2.0.0...v2.1.0) (2021-01-08) 62 | 63 | 64 | ### Features 65 | 66 | * optimize JSON assets added later by plugins ([10ebd05](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/commit/10ebd050b6ec802d3c414e3b618604f2391da956)) 67 | 68 | ## [2.0.0](https://github.com/webpack-contrib/json-minimizer-webpack-plugin/compare/v1.0.1...v2.0.0) (2020-11-09) 69 | 70 | 71 | ### ⚠ BREAKING CHANGES 72 | 73 | * minimum supported `webpack` version is `5.1.0` 74 | 75 | ## 1.0.1 (2020-10-07) 76 | 77 | 78 | ### Chore 79 | 80 | * update `schema-utils` 81 | 82 | ## 1.0.0 (2020-10-05) 83 | 84 | Initial release 85 | 86 | 87 | # Change Log 88 | 89 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-minimizer-webpack-plugin", 3 | "version": "5.0.1", 4 | "description": "json minimizer plugin for Webpack", 5 | "keywords": [ 6 | "json", 7 | "webpack", 8 | "webpack-plugin", 9 | "minimize", 10 | "minimizer", 11 | "minify", 12 | "minifier", 13 | "optimize", 14 | "optimizer" 15 | ], 16 | "homepage": "https://github.com/webpack/json-minimizer-webpack-plugin", 17 | "bugs": "https://github.com/webpack/json-minimizer-webpack-plugin/issues", 18 | "repository": "webpack/json-minimizer-webpack-plugin", 19 | "funding": { 20 | "type": "opencollective", 21 | "url": "https://opencollective.com/webpack" 22 | }, 23 | "license": "MIT", 24 | "author": "webpack Contrib Team", 25 | "main": "dist/index.js", 26 | "types": "types/index.d.ts", 27 | "files": [ 28 | "dist", 29 | "types" 30 | ], 31 | "scripts": { 32 | "start": "npm run build -- -w", 33 | "clean": "del-cli dist types", 34 | "prebuild": "npm run clean", 35 | "build:types": "tsc --declaration --emitDeclarationOnly --outDir types && prettier \"types/**/*.ts\" --write", 36 | "build:code": "cross-env NODE_ENV=production babel src -d dist --copy-files", 37 | "build": "npm-run-all -p \"build:**\"", 38 | "commitlint": "commitlint --from=main", 39 | "security": "npm audit --security", 40 | "lint:prettier": "prettier --cache --list-different .", 41 | "lint:js": "eslint --cache .", 42 | "lint:spelling": "cspell --cache --no-must-find-files --quiet \"**/*.*\"", 43 | "lint:types": "tsc --pretty --noEmit", 44 | "lint": "npm-run-all -l -p \"lint:**\"", 45 | "fix:js": "npm run lint:js -- --fix", 46 | "fix:prettier": "npm run lint:prettier -- --write", 47 | "fix": "npm-run-all -l fix:js fix:prettier", 48 | "test:only": "cross-env NODE_ENV=test jest", 49 | "test:watch": "npm run test:only -- --watch", 50 | "test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage", 51 | "pretest": "npm run lint", 52 | "test": "npm run test:coverage", 53 | "prepare": "husky install && npm run build", 54 | "release": "standard-version" 55 | }, 56 | "dependencies": { 57 | "schema-utils": "^4.2.0" 58 | }, 59 | "devDependencies": { 60 | "@babel/cli": "^7.24.6", 61 | "@babel/core": "^7.24.6", 62 | "@babel/preset-env": "^7.24.6", 63 | "@commitlint/cli": "^18.6.1", 64 | "@commitlint/config-conventional": "^18.6.2", 65 | "@eslint/js": "^9.32.0", 66 | "@eslint/markdown": "^7.1.0", 67 | "@stylistic/eslint-plugin": "^5.2.2", 68 | "@types/node": "^20.13.0", 69 | "babel-jest": "^30.0.0", 70 | "copy-webpack-plugin": "^13.0.0", 71 | "cross-env": "^7.0.3", 72 | "cspell": "^8.8.3", 73 | "del": "^7.1.0", 74 | "del-cli": "^5.1.0", 75 | "eslint": "^9.32.0", 76 | "eslint-config-prettier": "^10.1.8", 77 | "eslint-config-webpack": "^4.5.1", 78 | "eslint-plugin-import": "^2.32.0", 79 | "eslint-plugin-jest": "^29.0.1", 80 | "eslint-plugin-jsdoc": "^52.0.0", 81 | "eslint-plugin-n": "^17.21.1", 82 | "eslint-plugin-prettier": "^5.5.3", 83 | "eslint-plugin-unicorn": "^60.0.0", 84 | "globals": "^16.3.0", 85 | "husky": "^8.0.3", 86 | "jest": "^30.0.0", 87 | "lint-staged": "^15.2.5", 88 | "memfs": "^4.9.2", 89 | "npm-run-all": "^4.1.5", 90 | "prettier": "^3.2.5", 91 | "standard-version": "^9.5.0", 92 | "typescript": "^5.4.5", 93 | "typescript-eslint": "^8.38.0", 94 | "webpack": "^5.91.0" 95 | }, 96 | "peerDependencies": { 97 | "webpack": "^5.1.0" 98 | }, 99 | "engines": { 100 | "node": ">= 18.12.0" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /test/__snapshots__/exclude-option.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`exclude option should match snapshot for a single RegExp value exclude: assets 1`] = ` 4 | { 5 | "include-exclude/exclude-1.json": "{ 6 | "squadName": "Super hero squad", 7 | "homeTown": "Metro City", 8 | "formed": 2016, 9 | "secretBase": "Super tower", 10 | "active": true 11 | } 12 | ", 13 | "include-exclude/exclude-2.json": "{ 14 | "squadName": "Super hero squad", 15 | "homeTown": "Metro City", 16 | "formed": 2016, 17 | "secretBase": "Super tower", 18 | "active": true 19 | } 20 | ", 21 | "include-exclude/include-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 22 | "include-exclude/include-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 23 | "include-exclude/include-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 24 | "include-exclude/include-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 25 | } 26 | `; 27 | 28 | exports[`exclude option should match snapshot for a single RegExp value exclude: errors 1`] = `[]`; 29 | 30 | exports[`exclude option should match snapshot for a single RegExp value exclude: warnings 1`] = `[]`; 31 | 32 | exports[`exclude option should match snapshot for multiple RegExp values exclude: assets 1`] = ` 33 | { 34 | "include-exclude/exclude-1.json": "{ 35 | "squadName": "Super hero squad", 36 | "homeTown": "Metro City", 37 | "formed": 2016, 38 | "secretBase": "Super tower", 39 | "active": true 40 | } 41 | ", 42 | "include-exclude/exclude-2.json": "{ 43 | "squadName": "Super hero squad", 44 | "homeTown": "Metro City", 45 | "formed": 2016, 46 | "secretBase": "Super tower", 47 | "active": true 48 | } 49 | ", 50 | "include-exclude/include-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 51 | "include-exclude/include-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 52 | "include-exclude/include-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 53 | "include-exclude/include-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 54 | } 55 | `; 56 | 57 | exports[`exclude option should match snapshot for multiple RegExp values exclude: errors 1`] = `[]`; 58 | 59 | exports[`exclude option should match snapshot for multiple RegExp values exclude: warnings 1`] = `[]`; 60 | 61 | exports[`exclude option should match snapshot for multiple String values exclude: assets 1`] = ` 62 | { 63 | "include-exclude/exclude-1.json": "{ 64 | "squadName": "Super hero squad", 65 | "homeTown": "Metro City", 66 | "formed": 2016, 67 | "secretBase": "Super tower", 68 | "active": true 69 | } 70 | ", 71 | "include-exclude/exclude-2.json": "{ 72 | "squadName": "Super hero squad", 73 | "homeTown": "Metro City", 74 | "formed": 2016, 75 | "secretBase": "Super tower", 76 | "active": true 77 | } 78 | ", 79 | "include-exclude/include-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 80 | "include-exclude/include-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 81 | "include-exclude/include-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 82 | "include-exclude/include-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 83 | } 84 | `; 85 | 86 | exports[`exclude option should match snapshot for multiple String values exclude: errors 1`] = `[]`; 87 | 88 | exports[`exclude option should match snapshot for multiple String values exclude: warnings 1`] = `[]`; 89 | -------------------------------------------------------------------------------- /test/validate-options.test.js: -------------------------------------------------------------------------------- 1 | import JsonMinimizerPlugin from "../src"; 2 | 3 | describe("validation", () => { 4 | it("validation", () => { 5 | /* eslint-disable no-new */ 6 | expect(() => { 7 | new JsonMinimizerPlugin({ test: /foo/ }); 8 | }).not.toThrow(); 9 | 10 | expect(() => { 11 | new JsonMinimizerPlugin({ test: "foo" }); 12 | }).not.toThrow(); 13 | 14 | expect(() => { 15 | new JsonMinimizerPlugin({ test: [/foo/] }); 16 | }).not.toThrow(); 17 | 18 | expect(() => { 19 | new JsonMinimizerPlugin({ test: [/foo/, /bar/] }); 20 | }).not.toThrow(); 21 | 22 | expect(() => { 23 | new JsonMinimizerPlugin({ test: ["foo", "bar"] }); 24 | }).not.toThrow(); 25 | 26 | expect(() => { 27 | new JsonMinimizerPlugin({ test: [/foo/, "bar"] }); 28 | }).not.toThrow(); 29 | 30 | expect(() => { 31 | new JsonMinimizerPlugin({ test: true }); 32 | }).toThrowErrorMatchingSnapshot(); 33 | 34 | expect(() => { 35 | new JsonMinimizerPlugin({ test: [true] }); 36 | }).toThrowErrorMatchingSnapshot(); 37 | 38 | expect(() => { 39 | new JsonMinimizerPlugin({ include: /foo/ }); 40 | }).not.toThrow(); 41 | 42 | expect(() => { 43 | new JsonMinimizerPlugin({ include: "foo" }); 44 | }).not.toThrow(); 45 | 46 | expect(() => { 47 | new JsonMinimizerPlugin({ include: [/foo/] }); 48 | }).not.toThrow(); 49 | 50 | expect(() => { 51 | new JsonMinimizerPlugin({ include: [/foo/, /bar/] }); 52 | }).not.toThrow(); 53 | 54 | expect(() => { 55 | new JsonMinimizerPlugin({ include: ["foo", "bar"] }); 56 | }).not.toThrow(); 57 | 58 | expect(() => { 59 | new JsonMinimizerPlugin({ include: [/foo/, "bar"] }); 60 | }).not.toThrow(); 61 | 62 | expect(() => { 63 | new JsonMinimizerPlugin({ include: true }); 64 | }).toThrowErrorMatchingSnapshot(); 65 | 66 | expect(() => { 67 | new JsonMinimizerPlugin({ include: [true] }); 68 | }).toThrowErrorMatchingSnapshot(); 69 | 70 | expect(() => { 71 | new JsonMinimizerPlugin({ exclude: /foo/ }); 72 | }).not.toThrow(); 73 | 74 | expect(() => { 75 | new JsonMinimizerPlugin({ exclude: "foo" }); 76 | }).not.toThrow(); 77 | 78 | expect(() => { 79 | new JsonMinimizerPlugin({ exclude: [/foo/] }); 80 | }).not.toThrow(); 81 | 82 | expect(() => { 83 | new JsonMinimizerPlugin({ exclude: [/foo/, /bar/] }); 84 | }).not.toThrow(); 85 | 86 | expect(() => { 87 | new JsonMinimizerPlugin({ exclude: ["foo", "bar"] }); 88 | }).not.toThrow(); 89 | 90 | expect(() => { 91 | new JsonMinimizerPlugin({ exclude: [/foo/, "bar"] }); 92 | }).not.toThrow(); 93 | 94 | expect(() => { 95 | new JsonMinimizerPlugin({ exclude: true }); 96 | }).toThrowErrorMatchingSnapshot(); 97 | 98 | expect(() => { 99 | new JsonMinimizerPlugin({ exclude: [true] }); 100 | }).toThrowErrorMatchingSnapshot(); 101 | 102 | expect(() => { 103 | new JsonMinimizerPlugin({ minimizerOptions: {} }); 104 | }).not.toThrow(); 105 | 106 | expect(() => { 107 | new JsonMinimizerPlugin({ minimizerOptions: { replacer: ["test", 2] } }); 108 | }).not.toThrow(); 109 | 110 | expect(() => { 111 | new JsonMinimizerPlugin({ minimizerOptions: { replacer: () => {} } }); 112 | }).not.toThrow(); 113 | 114 | expect(() => { 115 | new JsonMinimizerPlugin({ minimizerOptions: { replacer: null } }); 116 | }).not.toThrow(); 117 | 118 | expect(() => { 119 | new JsonMinimizerPlugin({ minimizerOptions: { space: 2 } }); 120 | }).not.toThrow(); 121 | 122 | expect(() => { 123 | new JsonMinimizerPlugin({ minimizerOptions: { space: " " } }); 124 | }).not.toThrow(); 125 | 126 | expect(() => { 127 | new JsonMinimizerPlugin({ minimizerOptions: { space: null } }); 128 | }).not.toThrow(); 129 | 130 | expect(() => { 131 | new JsonMinimizerPlugin({ minimizerOptions: null }); 132 | }).toThrowErrorMatchingSnapshot(); 133 | 134 | expect(() => { 135 | new JsonMinimizerPlugin({ unknown: true }); 136 | }).toThrowErrorMatchingSnapshot(); 137 | /* eslint-enable no-new */ 138 | }); 139 | }); 140 | -------------------------------------------------------------------------------- /test/__snapshots__/include-option.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`include option should match snapshot for a single RegExp value include: assets 1`] = ` 4 | { 5 | "include-exclude/exclude-1.json": "{ 6 | "squadName": "Super hero squad", 7 | "homeTown": "Metro City", 8 | "formed": 2016, 9 | "secretBase": "Super tower", 10 | "active": true 11 | } 12 | ", 13 | "include-exclude/exclude-2.json": "{ 14 | "squadName": "Super hero squad", 15 | "homeTown": "Metro City", 16 | "formed": 2016, 17 | "secretBase": "Super tower", 18 | "active": true 19 | } 20 | ", 21 | "include-exclude/include-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 22 | "include-exclude/include-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 23 | "include-exclude/include-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 24 | "include-exclude/include-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 25 | } 26 | `; 27 | 28 | exports[`include option should match snapshot for a single RegExp value include: errors 1`] = `[]`; 29 | 30 | exports[`include option should match snapshot for a single RegExp value include: warnings 1`] = `[]`; 31 | 32 | exports[`include option should match snapshot for multiple RegExp values include: assets 1`] = ` 33 | { 34 | "include-exclude/exclude-1.json": "{ 35 | "squadName": "Super hero squad", 36 | "homeTown": "Metro City", 37 | "formed": 2016, 38 | "secretBase": "Super tower", 39 | "active": true 40 | } 41 | ", 42 | "include-exclude/exclude-2.json": "{ 43 | "squadName": "Super hero squad", 44 | "homeTown": "Metro City", 45 | "formed": 2016, 46 | "secretBase": "Super tower", 47 | "active": true 48 | } 49 | ", 50 | "include-exclude/include-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 51 | "include-exclude/include-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 52 | "include-exclude/include-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 53 | "include-exclude/include-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 54 | } 55 | `; 56 | 57 | exports[`include option should match snapshot for multiple RegExp values include: errors 1`] = `[]`; 58 | 59 | exports[`include option should match snapshot for multiple RegExp values include: warnings 1`] = `[]`; 60 | 61 | exports[`include option should match snapshot for multiple String values include: assets 1`] = ` 62 | { 63 | "include-exclude/exclude-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 64 | "include-exclude/exclude-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 65 | "include-exclude/include-1.json": "{ 66 | "squadName": "Super hero squad", 67 | "homeTown": "Metro City", 68 | "formed": 2016, 69 | "secretBase": "Super tower", 70 | "active": true 71 | } 72 | ", 73 | "include-exclude/include-2.json": "{ 74 | "squadName": "Super hero squad", 75 | "homeTown": "Metro City", 76 | "formed": 2016, 77 | "secretBase": "Super tower", 78 | "active": true 79 | } 80 | ", 81 | "include-exclude/include-3.json": "{ 82 | "squadName": "Super hero squad", 83 | "homeTown": "Metro City", 84 | "formed": 2016, 85 | "secretBase": "Super tower", 86 | "active": true 87 | } 88 | ", 89 | "include-exclude/include-4.json": "{ 90 | "squadName": "Super hero squad", 91 | "homeTown": "Metro City", 92 | "formed": 2016, 93 | "secretBase": "Super tower", 94 | "active": true 95 | } 96 | ", 97 | } 98 | `; 99 | 100 | exports[`include option should match snapshot for multiple String values include: errors 1`] = `[]`; 101 | 102 | exports[`include option should match snapshot for multiple String values include: warnings 1`] = `[]`; 103 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | export = JsonMinimizerPlugin; 2 | /** @typedef {import("schema-utils/declarations/validate").Schema} Schema */ 3 | /** @typedef {import("webpack").Compiler} Compiler */ 4 | /** @typedef {import("webpack").Compilation} Compilation */ 5 | /** @typedef {import("webpack").Asset} Asset */ 6 | /** @typedef {import("webpack").WebpackError} WebpackError */ 7 | /** @typedef {RegExp | string} Rule */ 8 | /** @typedef {Rule[] | Rule} Rules */ 9 | /** 10 | * @typedef {object} JSONOptions 11 | * @property {(this: unknown, key: string, value: unknown) => unknown | (number | string)[] | null=} replacer JSON replacer function or array 12 | * @property {string | number=} space JSON space parameter for formatting 13 | */ 14 | /** 15 | * @typedef {object} BasePluginOptions 16 | * @property {Rule=} test Test pattern for matching files 17 | * @property {Rule=} include Include pattern for files 18 | * @property {Rule=} exclude Exclude pattern for files 19 | * @property {JSONOptions=} minimizerOptions Options for JSON minimization 20 | */ 21 | /** 22 | * @typedef {object} MinimizedResult 23 | * @property {string} code The minimized JSON code 24 | */ 25 | /** 26 | * @typedef {object} InternalOptions 27 | * @property {string} input The input JSON string to minimize 28 | * @property {JSONOptions=} minimizerOptions Options for JSON minimization 29 | */ 30 | /** 31 | * @typedef {BasePluginOptions} PluginOptions 32 | */ 33 | declare class JsonMinimizerPlugin { 34 | /** 35 | * Build an error message for JSON minimization failures 36 | * @param {unknown} error The error that occurred 37 | * @param {string} file The file being processed 38 | * @param {string} context The compilation context 39 | * @returns {Error} Formatted error message 40 | */ 41 | static buildError(error: unknown, file: string, context: string): Error; 42 | /** 43 | * Create a new JsonMinimizerPlugin instance 44 | * @param {PluginOptions} options Plugin configuration options 45 | */ 46 | constructor(options?: PluginOptions); 47 | /** 48 | * @type {PluginOptions} 49 | */ 50 | options: PluginOptions; 51 | /** 52 | * Optimize assets by minimizing JSON files 53 | * @param {Compiler} compiler The webpack compiler instance 54 | * @param {Compilation} compilation The webpack compilation instance 55 | * @param {Record} assets The assets to process 56 | * @returns {Promise} Promise that resolves when optimization is complete 57 | */ 58 | optimize( 59 | compiler: Compiler, 60 | compilation: Compilation, 61 | assets: Record, 62 | ): Promise; 63 | /** 64 | * Apply the plugin to the webpack compiler 65 | * @param {Compiler} compiler The webpack compiler instance 66 | * @returns {void} 67 | */ 68 | apply(compiler: Compiler): void; 69 | } 70 | declare namespace JsonMinimizerPlugin { 71 | export { 72 | Schema, 73 | Compiler, 74 | Compilation, 75 | Asset, 76 | WebpackError, 77 | Rule, 78 | Rules, 79 | JSONOptions, 80 | BasePluginOptions, 81 | MinimizedResult, 82 | InternalOptions, 83 | PluginOptions, 84 | }; 85 | } 86 | type Schema = import("schema-utils/declarations/validate").Schema; 87 | type Compiler = import("webpack").Compiler; 88 | type Compilation = import("webpack").Compilation; 89 | type Asset = import("webpack").Asset; 90 | type WebpackError = import("webpack").WebpackError; 91 | type Rule = RegExp | string; 92 | type Rules = Rule[] | Rule; 93 | type JSONOptions = { 94 | /** 95 | * JSON replacer function or array 96 | */ 97 | replacer?: 98 | | (( 99 | this: unknown, 100 | key: string, 101 | value: unknown, 102 | ) => unknown | (number | string)[] | null) 103 | | undefined; 104 | /** 105 | * JSON space parameter for formatting 106 | */ 107 | space?: (string | number) | undefined; 108 | }; 109 | type BasePluginOptions = { 110 | /** 111 | * Test pattern for matching files 112 | */ 113 | test?: Rule | undefined; 114 | /** 115 | * Include pattern for files 116 | */ 117 | include?: Rule | undefined; 118 | /** 119 | * Exclude pattern for files 120 | */ 121 | exclude?: Rule | undefined; 122 | /** 123 | * Options for JSON minimization 124 | */ 125 | minimizerOptions?: JSONOptions | undefined; 126 | }; 127 | type MinimizedResult = { 128 | /** 129 | * The minimized JSON code 130 | */ 131 | code: string; 132 | }; 133 | type InternalOptions = { 134 | /** 135 | * The input JSON string to minimize 136 | */ 137 | input: string; 138 | /** 139 | * Options for JSON minimization 140 | */ 141 | minimizerOptions?: JSONOptions | undefined; 142 | }; 143 | type PluginOptions = BasePluginOptions; 144 | -------------------------------------------------------------------------------- /test/__snapshots__/validate-options.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing 2 | 3 | exports[`validation validation 1`] = ` 4 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 5 | - options.test should be one of these: 6 | [RegExp | non-empty string, ...] | RegExp | non-empty string 7 | -> Filtering rules. 8 | -> Read more at https://github.com/webpack/json-minimizer-webpack-plugin#test 9 | Details: 10 | * options.test should be an array: 11 | [RegExp | non-empty string, ...] 12 | * options.test should be one of these: 13 | RegExp | non-empty string 14 | -> Filtering rule as regex or string. 15 | Details: 16 | * options.test should be an instance of RegExp. 17 | * options.test should be a non-empty string." 18 | `; 19 | 20 | exports[`validation validation 2`] = ` 21 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 22 | - options.test should be one of these: 23 | [RegExp | non-empty string, ...] | RegExp | non-empty string 24 | -> Filtering rules. 25 | -> Read more at https://github.com/webpack/json-minimizer-webpack-plugin#test 26 | Details: 27 | * options.test[0] should be one of these: 28 | RegExp | non-empty string 29 | -> Filtering rule as regex or string. 30 | Details: 31 | * options.test[0] should be an instance of RegExp. 32 | * options.test[0] should be a non-empty string." 33 | `; 34 | 35 | exports[`validation validation 3`] = ` 36 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 37 | - options.include should be one of these: 38 | [RegExp | non-empty string, ...] | RegExp | non-empty string 39 | -> Filtering rules. 40 | -> Read more at https://github.com/webpack/json-minimizer-webpack-plugin#include 41 | Details: 42 | * options.include should be an array: 43 | [RegExp | non-empty string, ...] 44 | * options.include should be one of these: 45 | RegExp | non-empty string 46 | -> Filtering rule as regex or string. 47 | Details: 48 | * options.include should be an instance of RegExp. 49 | * options.include should be a non-empty string." 50 | `; 51 | 52 | exports[`validation validation 4`] = ` 53 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 54 | - options.include should be one of these: 55 | [RegExp | non-empty string, ...] | RegExp | non-empty string 56 | -> Filtering rules. 57 | -> Read more at https://github.com/webpack/json-minimizer-webpack-plugin#include 58 | Details: 59 | * options.include[0] should be one of these: 60 | RegExp | non-empty string 61 | -> Filtering rule as regex or string. 62 | Details: 63 | * options.include[0] should be an instance of RegExp. 64 | * options.include[0] should be a non-empty string." 65 | `; 66 | 67 | exports[`validation validation 5`] = ` 68 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 69 | - options.exclude should be one of these: 70 | [RegExp | non-empty string, ...] | RegExp | non-empty string 71 | -> Filtering rules. 72 | -> Read more at https://github.com/webpack/json-minimizer-webpack-plugin#exclude 73 | Details: 74 | * options.exclude should be an array: 75 | [RegExp | non-empty string, ...] 76 | * options.exclude should be one of these: 77 | RegExp | non-empty string 78 | -> Filtering rule as regex or string. 79 | Details: 80 | * options.exclude should be an instance of RegExp. 81 | * options.exclude should be a non-empty string." 82 | `; 83 | 84 | exports[`validation validation 6`] = ` 85 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 86 | - options.exclude should be one of these: 87 | [RegExp | non-empty string, ...] | RegExp | non-empty string 88 | -> Filtering rules. 89 | -> Read more at https://github.com/webpack/json-minimizer-webpack-plugin#exclude 90 | Details: 91 | * options.exclude[0] should be one of these: 92 | RegExp | non-empty string 93 | -> Filtering rule as regex or string. 94 | Details: 95 | * options.exclude[0] should be an instance of RegExp. 96 | * options.exclude[0] should be a non-empty string." 97 | `; 98 | 99 | exports[`validation validation 7`] = ` 100 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 101 | - options.minimizerOptions should be an object: 102 | object { replacer?, space? } 103 | -> Options for \`jsonMinimizerOptions\`. 104 | -> Read more at https://github.com/webpack/json-minimizer-webpack-plugin#minimizeroptions" 105 | `; 106 | 107 | exports[`validation validation 8`] = ` 108 | "Invalid options object. Json Minimizer Plugin has been initialized using an options object that does not match the API schema. 109 | - options has an unknown property 'unknown'. These properties are valid: 110 | object { test?, include?, exclude?, minimizerOptions? }" 111 | `; 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | [![npm][npm]][npm-url] 8 | [![node][node]][node-url] 9 | [![tests][tests]][tests-url] 10 | [![cover][cover]][cover-url] 11 | [![discussion][discussion]][discussion-url] 12 | [![size][size]][size-url] 13 | 14 | # json-minimizer-webpack-plugin 15 | 16 | This plugin uses [JSON.stringify()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) to minify your JSON files during the build process. 17 | 18 | ## Getting Started 19 | 20 | To begin, you'll need to install `json-minimizer-webpack-plugin`: 21 | 22 | ```console 23 | npm install json-minimizer-webpack-plugin --save-dev 24 | ``` 25 | 26 | or 27 | 28 | ```console 29 | yarn add -D json-minimizer-webpack-plugin 30 | ``` 31 | 32 | or 33 | 34 | ```console 35 | pnpm add -D json-minimizer-webpack-plugin 36 | ``` 37 | 38 | Then add the plugin to your `webpack` configuration. For example: 39 | 40 | **webpack.config.js** 41 | 42 | ```js 43 | const CopyPlugin = require("copy-webpack-plugin"); 44 | const JsonMinimizerPlugin = require("json-minimizer-webpack-plugin"); 45 | 46 | module.exports = { 47 | module: { 48 | rules: [ 49 | { 50 | test: /\.json$/i, 51 | type: "asset/resource", 52 | }, 53 | ], 54 | }, 55 | plugins: [ 56 | new CopyPlugin({ 57 | patterns: [ 58 | { 59 | context: path.resolve(__dirname, "dist"), 60 | from: "./src/*.json", 61 | }, 62 | ], 63 | }), 64 | ], 65 | optimization: { 66 | minimize: true, 67 | minimizer: [ 68 | // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line 69 | // `...` 70 | new JsonMinimizerPlugin(), 71 | ], 72 | }, 73 | }; 74 | ``` 75 | 76 | Finally, run `webpack` using the method you normally use (e.g., via CLI or an npm script). 77 | 78 | ## Options 79 | 80 | - **[`test`](#test)** 81 | - **[`include`](#include)** 82 | - **[`exclude`](#exclude)** 83 | - **[`minimizerOptions`](#minimizeroptions)** 84 | 85 | ### `test` 86 | 87 | Type: 88 | 89 | ```ts 90 | type test = string | RegExp | (string | RegExp)[]; 91 | ``` 92 | 93 | Default: `/\.json(\?.*)?$/i` 94 | 95 | Test to match files against. 96 | 97 | ```js 98 | module.exports = { 99 | optimization: { 100 | minimize: true, 101 | minimizer: [ 102 | new JsonMinimizerPlugin({ 103 | test: /\.foo\.json/i, 104 | }), 105 | ], 106 | }, 107 | }; 108 | ``` 109 | 110 | ### `include` 111 | 112 | Type: 113 | 114 | ```ts 115 | type include = string | RegExp | (string | RegExp)[]; 116 | ``` 117 | 118 | Default: `undefined` 119 | 120 | Files to include for minimization. 121 | 122 | **webpack.config.js** 123 | 124 | ```js 125 | module.exports = { 126 | optimization: { 127 | minimize: true, 128 | minimizer: [ 129 | new JsonMinimizerPlugin({ 130 | include: /\/includes/, 131 | }), 132 | ], 133 | }, 134 | }; 135 | ``` 136 | 137 | ### `exclude` 138 | 139 | Type: 140 | 141 | ```ts 142 | type exclude = string | RegExp | (string | RegExp)[]; 143 | ``` 144 | 145 | Default: `undefined` 146 | 147 | Files to exclude from minimization. 148 | 149 | **webpack.config.js** 150 | 151 | ```js 152 | module.exports = { 153 | optimization: { 154 | minimize: true, 155 | minimizer: [ 156 | new JsonMinimizerPlugin({ 157 | exclude: /\/excludes/, 158 | }), 159 | ], 160 | }, 161 | }; 162 | ``` 163 | 164 | ### `minimizerOptions` 165 | 166 | Type: 167 | 168 | 169 | 170 | ```ts 171 | interface minimizerOptions { 172 | space?: null | string | number; 173 | replacer?: null | Function | (string | number)[]; 174 | } 175 | ``` 176 | 177 | Default: `{ replacer: null, space: null }` 178 | 179 | `JSON.stringify()` [options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). 180 | 181 | ```js 182 | module.exports = { 183 | optimization: { 184 | minimize: true, 185 | minimizer: [ 186 | new JsonMinimizerPlugin({ 187 | minimizerOptions: { 188 | space: "\t", 189 | }, 190 | }), 191 | ], 192 | }, 193 | }; 194 | ``` 195 | 196 | ## Contributing 197 | 198 | We welcome all contributions! 199 | If you're new here, please take a moment to review our contributing guidelines before submitting issues or pull requests. 200 | 201 | [CONTRIBUTING](https://github.com/webpack/json-minimizer-webpack-plugin?tab=contributing-ov-file#contributing) 202 | 203 | ## License 204 | 205 | [MIT](./LICENSE) 206 | 207 | [npm]: https://img.shields.io/npm/v/json-minimizer-webpack-plugin.svg 208 | [npm-url]: https://npmjs.com/package/json-minimizer-webpack-plugin 209 | [node]: https://img.shields.io/node/v/json-minimizer-webpack-plugin.svg 210 | [node-url]: https://nodejs.org 211 | [tests]: https://github.com/webpack/json-minimizer-webpack-plugin/workflows/json-minimizer-webpack-plugin/badge.svg 212 | [tests-url]: https://github.com/webpack/json-minimizer-webpack-plugin/actions 213 | [cover]: https://codecov.io/gh/webpack/json-minimizer-webpack-plugin/branch/main/graph/badge.svg 214 | [cover-url]: https://codecov.io/gh/webpack/json-minimizer-webpack-plugin 215 | [discussion]: https://img.shields.io/github/discussions/webpack/webpack 216 | [discussion-url]: https://github.com/webpack/webpack/discussions 217 | [size]: https://packagephobia.now.sh/badge?p=json-minimizer-webpack-plugin 218 | [size-url]: https://packagephobia.now.sh/result?p=json-minimizer-webpack-plugin 219 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const { validate } = require("schema-utils"); 2 | 3 | const { minify: internalMinify } = require("./minify"); 4 | const schema = require("./options.json"); 5 | 6 | /** @typedef {import("schema-utils/declarations/validate").Schema} Schema */ 7 | /** @typedef {import("webpack").Compiler} Compiler */ 8 | /** @typedef {import("webpack").Compilation} Compilation */ 9 | /** @typedef {import("webpack").Asset} Asset */ 10 | /** @typedef {import("webpack").WebpackError} WebpackError */ 11 | 12 | /** @typedef {RegExp | string} Rule */ 13 | /** @typedef {Rule[] | Rule} Rules */ 14 | 15 | /** 16 | * @typedef {object} JSONOptions 17 | * @property {(this: unknown, key: string, value: unknown) => unknown | (number | string)[] | null=} replacer JSON replacer function or array 18 | * @property {string | number=} space JSON space parameter for formatting 19 | */ 20 | 21 | /** 22 | * @typedef {object} BasePluginOptions 23 | * @property {Rule=} test Test pattern for matching files 24 | * @property {Rule=} include Include pattern for files 25 | * @property {Rule=} exclude Exclude pattern for files 26 | * @property {JSONOptions=} minimizerOptions Options for JSON minimization 27 | */ 28 | 29 | /** 30 | * @typedef {object} MinimizedResult 31 | * @property {string} code The minimized JSON code 32 | */ 33 | 34 | /** 35 | * @typedef {object} InternalOptions 36 | * @property {string} input The input JSON string to minimize 37 | * @property {JSONOptions=} minimizerOptions Options for JSON minimization 38 | */ 39 | 40 | /** 41 | * @typedef {BasePluginOptions} PluginOptions 42 | */ 43 | 44 | class JsonMinimizerPlugin { 45 | /** 46 | * Create a new JsonMinimizerPlugin instance 47 | * @param {PluginOptions} options Plugin configuration options 48 | */ 49 | constructor(options = {}) { 50 | validate(/** @type {Schema} */ (schema), options, { 51 | name: "Json Minimizer Plugin", 52 | baseDataPath: "options", 53 | }); 54 | 55 | const { 56 | minimizerOptions = {}, 57 | test = /\.json(\?.*)?$/i, 58 | include, 59 | exclude, 60 | } = options; 61 | 62 | /** 63 | * @type {PluginOptions} 64 | */ 65 | this.options = { 66 | test, 67 | include, 68 | exclude, 69 | minimizerOptions, 70 | }; 71 | } 72 | 73 | /** 74 | * Build an error message for JSON minimization failures 75 | * @param {unknown} error The error that occurred 76 | * @param {string} file The file being processed 77 | * @param {string} context The compilation context 78 | * @returns {Error} Formatted error message 79 | */ 80 | static buildError(error, file, context) { 81 | return new Error( 82 | `"${file}" in "${context}" from Json Minimizer:\n${error}`, 83 | ); 84 | } 85 | 86 | /** 87 | * Optimize assets by minimizing JSON files 88 | * @param {Compiler} compiler The webpack compiler instance 89 | * @param {Compilation} compilation The webpack compilation instance 90 | * @param {Record} assets The assets to process 91 | * @returns {Promise} Promise that resolves when optimization is complete 92 | */ 93 | async optimize(compiler, compilation, assets) { 94 | const cache = compilation.getCache("JsonMinimizerWebpackPlugin"); 95 | const assetsForMinify = await Promise.all( 96 | Object.keys(assets) 97 | .filter((name) => { 98 | const { info } = /** @type {Asset} */ (compilation.getAsset(name)); 99 | 100 | // Skip double minimize assets from child compilation 101 | if (info.minimized) { 102 | return false; 103 | } 104 | 105 | if ( 106 | !compiler.webpack.ModuleFilenameHelpers.matchObject.bind( 107 | undefined, 108 | this.options, 109 | )(name) 110 | ) { 111 | return false; 112 | } 113 | 114 | return true; 115 | }) 116 | .map(async (name) => { 117 | const { info, source } = /** @type {Asset} */ ( 118 | compilation.getAsset(name) 119 | ); 120 | 121 | const eTag = cache.getLazyHashedEtag(source); 122 | const cacheItem = cache.getItemCache(name, eTag); 123 | const output = await cacheItem.getPromise(); 124 | 125 | return { name, info, inputSource: source, output, cacheItem }; 126 | }), 127 | ); 128 | 129 | const { RawSource } = compiler.webpack.sources; 130 | 131 | const scheduledTasks = []; 132 | 133 | for (const asset of assetsForMinify) { 134 | scheduledTasks.push( 135 | (async () => { 136 | const { name, inputSource, cacheItem } = asset; 137 | let { output } = asset; 138 | let input; 139 | 140 | const sourceFromInputSource = inputSource.source(); 141 | 142 | if (!output) { 143 | input = sourceFromInputSource; 144 | 145 | if (Buffer.isBuffer(input)) { 146 | input = input.toString(); 147 | } 148 | 149 | /** 150 | * @type {InternalOptions} 151 | */ 152 | const options = { 153 | input, 154 | minimizerOptions: this.options.minimizerOptions, 155 | }; 156 | 157 | try { 158 | output = await internalMinify(options); 159 | } catch (error) { 160 | compilation.errors.push( 161 | /** @type {WebpackError} */ ( 162 | JsonMinimizerPlugin.buildError(error, name, compiler.context) 163 | ), 164 | ); 165 | 166 | return; 167 | } 168 | 169 | output.source = new RawSource(output.code); 170 | 171 | await cacheItem.storePromise({ 172 | source: output.source, 173 | }); 174 | } 175 | 176 | const newInfo = { minimized: true }; 177 | const { source } = output; 178 | 179 | compilation.updateAsset(name, source, newInfo); 180 | })(), 181 | ); 182 | } 183 | 184 | Promise.all(scheduledTasks); 185 | } 186 | 187 | /** 188 | * Apply the plugin to the webpack compiler 189 | * @param {Compiler} compiler The webpack compiler instance 190 | * @returns {void} 191 | */ 192 | apply(compiler) { 193 | const pluginName = this.constructor.name; 194 | 195 | compiler.hooks.compilation.tap(pluginName, (compilation) => { 196 | compilation.hooks.processAssets.tapPromise( 197 | { 198 | name: pluginName, 199 | stage: 200 | compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE, 201 | additionalAssets: true, 202 | }, 203 | (assets) => this.optimize(compiler, compilation, assets), 204 | ); 205 | 206 | compilation.hooks.statsPrinter.tap(pluginName, (stats) => { 207 | stats.hooks.print 208 | .for("asset.info.minimized") 209 | .tap( 210 | "json-minimizer-webpack-plugin", 211 | (minimized, { green, formatFlag }) => 212 | minimized 213 | ? /** @type {(text: string) => string} */ (green)( 214 | /** @type {(flag: string) => string} */ (formatFlag)( 215 | "minimized", 216 | ), 217 | ) 218 | : "", 219 | ); 220 | }); 221 | }); 222 | } 223 | } 224 | 225 | module.exports = JsonMinimizerPlugin; 226 | -------------------------------------------------------------------------------- /test/JsonMinimizerPlugin.test.js: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | 3 | import JsonMinimizerPlugin from "../src/index"; 4 | 5 | import { 6 | EmitNewAsset, 7 | ModifyExistingAsset, 8 | compile, 9 | getCompiler, 10 | getErrors, 11 | getWarnings, 12 | readAssets, 13 | } from "./helpers"; 14 | 15 | describe("JsonMinimizerPlugin", () => { 16 | it("should work (without options)", async () => { 17 | const testJsonId = "./simple.json"; 18 | const compiler = getCompiler(testJsonId); 19 | 20 | new JsonMinimizerPlugin().apply(compiler); 21 | 22 | const stats = await compile(compiler); 23 | 24 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 25 | expect(getErrors(stats)).toMatchSnapshot("errors"); 26 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 27 | }); 28 | 29 | it("should work with array", async () => { 30 | const testJsonId = "./array.json"; 31 | const compiler = getCompiler(testJsonId); 32 | 33 | new JsonMinimizerPlugin().apply(compiler); 34 | 35 | const stats = await compile(compiler); 36 | 37 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 38 | expect(getErrors(stats)).toMatchSnapshot("errors"); 39 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 40 | }); 41 | 42 | it("should emit error when an empty file", async () => { 43 | const testJsonId = "./empty.json"; 44 | const compiler = getCompiler(testJsonId); 45 | 46 | new JsonMinimizerPlugin().apply(compiler); 47 | 48 | const stats = await compile(compiler); 49 | 50 | expect(getErrors(stats)).toMatchSnapshot("errors"); 51 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 52 | }); 53 | 54 | it("should work without files", async () => { 55 | const testJsonId = "./simple.json"; 56 | const compiler = getCompiler(testJsonId); 57 | 58 | new JsonMinimizerPlugin({ 59 | include: "nothing", 60 | }).apply(compiler); 61 | 62 | const stats = await compile(compiler); 63 | 64 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 65 | expect(getErrors(stats)).toMatchSnapshot("errors"); 66 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 67 | }); 68 | 69 | it("should work with child compilation", async () => { 70 | const testJsonId = "./simple.json"; 71 | const compiler = getCompiler(testJsonId, { 72 | module: { 73 | rules: [ 74 | { 75 | test: /entry.js$/i, 76 | use: [ 77 | { 78 | loader: path.resolve( 79 | __dirname, 80 | "./helpers/emitAssetInChildCompilationLoader", 81 | ), 82 | }, 83 | ], 84 | }, 85 | ], 86 | }, 87 | }); 88 | 89 | new JsonMinimizerPlugin().apply(compiler); 90 | 91 | const stats = await compile(compiler); 92 | 93 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 94 | expect(getErrors(stats)).toMatchSnapshot("errors"); 95 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 96 | }); 97 | 98 | it("should emit error when broken json syntax", async () => { 99 | const testJsonId = "./broken-json-syntax.json"; 100 | const compiler = getCompiler(testJsonId); 101 | 102 | new JsonMinimizerPlugin().apply(compiler); 103 | 104 | const stats = await compile(compiler); 105 | const statsErrors = getErrors(stats); 106 | 107 | expect(statsErrors[0]).toContain( 108 | 'Error: "broken-json-syntax.json" in "/test/fixtures" from Json Minimizer:', 109 | ); 110 | 111 | const match = process.version.match( 112 | /^v(\d{1,2})\.(\d{1,2})\.(\d{1,2})(?:-([0-9A-Za-z-.]+))?(?:\+([0-9A-Za-z-.]+))?$/, 113 | ); 114 | 115 | if (Number.parseInt(match[1], 10) >= 20) { 116 | expect(statsErrors[0]).toContain( 117 | "SyntaxError: Expected property name or '}' in JSON at position 4", 118 | ); 119 | } else { 120 | expect(statsErrors[0]).toContain( 121 | "SyntaxError: Unexpected token s in JSON at position 4", 122 | ); 123 | } 124 | 125 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 126 | }); 127 | 128 | it('should work and use cache by default in "development" mode', async () => { 129 | const testJsonId = false; 130 | const compiler = getCompiler(testJsonId, { 131 | mode: "development", 132 | entry: { 133 | foo: path.resolve(__dirname, "./fixtures/cache.js"), 134 | }, 135 | }); 136 | 137 | new JsonMinimizerPlugin().apply(compiler); 138 | 139 | const stats = await compile(compiler); 140 | 141 | expect(stats.compilation.emittedAssets.size).toBe(6); 142 | 143 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("result"); 144 | expect(getErrors(stats)).toMatchSnapshot("errors"); 145 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 146 | 147 | await new Promise((resolve) => { 148 | compile(compiler).then((newStats) => { 149 | expect(newStats.compilation.emittedAssets.size).toBe(0); 150 | 151 | expect(readAssets(compiler, newStats, /\.json$/i)).toMatchSnapshot( 152 | "assets", 153 | ); 154 | expect(getWarnings(newStats)).toMatchSnapshot("errors"); 155 | expect(getErrors(newStats)).toMatchSnapshot("warnings"); 156 | 157 | resolve(); 158 | }); 159 | }); 160 | }); 161 | 162 | it("should work and use memory cache", async () => { 163 | const testJsonId = false; 164 | const compiler = getCompiler(testJsonId, { 165 | cache: { type: "memory" }, 166 | entry: { 167 | foo: path.resolve(__dirname, "./fixtures/cache.js"), 168 | }, 169 | }); 170 | 171 | new JsonMinimizerPlugin().apply(compiler); 172 | 173 | const stats = await compile(compiler); 174 | 175 | expect(stats.compilation.emittedAssets.size).toBe(6); 176 | 177 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("result"); 178 | expect(getErrors(stats)).toMatchSnapshot("errors"); 179 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 180 | 181 | await new Promise((resolve) => { 182 | compile(compiler).then((newStats) => { 183 | expect(newStats.compilation.emittedAssets.size).toBe(0); 184 | 185 | expect(readAssets(compiler, newStats, /\.json$/i)).toMatchSnapshot( 186 | "assets", 187 | ); 188 | expect(getWarnings(newStats)).toMatchSnapshot("errors"); 189 | expect(getErrors(newStats)).toMatchSnapshot("warnings"); 190 | 191 | resolve(); 192 | }); 193 | }); 194 | }); 195 | 196 | it('should work and use memory cache when the "cache" option is "true"', async () => { 197 | const testJsonId = false; 198 | const compiler = getCompiler(testJsonId, { 199 | cache: true, 200 | entry: { 201 | foo: path.resolve(__dirname, "./fixtures/cache.js"), 202 | }, 203 | }); 204 | 205 | new JsonMinimizerPlugin().apply(compiler); 206 | 207 | const stats = await compile(compiler); 208 | 209 | expect(stats.compilation.emittedAssets.size).toBe(6); 210 | 211 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("result"); 212 | expect(getErrors(stats)).toMatchSnapshot("errors"); 213 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 214 | 215 | await new Promise((resolve) => { 216 | compile(compiler).then((newStats) => { 217 | expect(newStats.compilation.emittedAssets.size).toBe(0); 218 | 219 | expect(readAssets(compiler, newStats, /\.json$/i)).toMatchSnapshot( 220 | "assets", 221 | ); 222 | expect(getWarnings(newStats)).toMatchSnapshot("errors"); 223 | expect(getErrors(newStats)).toMatchSnapshot("warnings"); 224 | 225 | resolve(); 226 | }); 227 | }); 228 | }); 229 | 230 | it('should work and use memory cache when the "cache" option is "true" and the asset has been changed', async () => { 231 | const testJsonId = false; 232 | const compiler = getCompiler(testJsonId, { 233 | cache: true, 234 | entry: { 235 | foo: path.resolve(__dirname, "./fixtures/cache.js"), 236 | }, 237 | }); 238 | 239 | new JsonMinimizerPlugin().apply(compiler); 240 | 241 | const stats = await compile(compiler); 242 | 243 | expect(stats.compilation.emittedAssets.size).toBe(6); 244 | 245 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("result"); 246 | expect(getErrors(stats)).toMatchSnapshot("errors"); 247 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 248 | 249 | new ModifyExistingAsset({ name: "cache.json" }).apply(compiler); 250 | new ModifyExistingAsset({ name: "cache-1.json" }).apply(compiler); 251 | 252 | await new Promise((resolve) => { 253 | compile(compiler).then((newStats) => { 254 | expect(newStats.compilation.emittedAssets.size).toBe(2); 255 | 256 | expect(readAssets(compiler, newStats, /\.json$/i)).toMatchSnapshot( 257 | "assets", 258 | ); 259 | expect(getWarnings(newStats)).toMatchSnapshot("errors"); 260 | expect(getErrors(newStats)).toMatchSnapshot("warnings"); 261 | 262 | resolve(); 263 | }); 264 | }); 265 | }); 266 | 267 | it('should work and do not use memory cache when the "cache" option is "false"', async () => { 268 | const testJsonId = false; 269 | const compiler = getCompiler(testJsonId, { 270 | cache: false, 271 | entry: { 272 | foo: path.resolve(__dirname, "./fixtures/cache.js"), 273 | }, 274 | }); 275 | 276 | new JsonMinimizerPlugin().apply(compiler); 277 | 278 | const stats = await compile(compiler); 279 | 280 | expect(stats.compilation.emittedAssets.size).toBe(6); 281 | 282 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("result"); 283 | expect(getErrors(stats)).toMatchSnapshot("errors"); 284 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 285 | 286 | await new Promise((resolve) => { 287 | compile(compiler).then((newStats) => { 288 | expect(newStats.compilation.emittedAssets.size).toBe(6); 289 | 290 | expect(readAssets(compiler, newStats, /\.json$/i)).toMatchSnapshot( 291 | "assets", 292 | ); 293 | expect(getWarnings(newStats)).toMatchSnapshot("errors"); 294 | expect(getErrors(newStats)).toMatchSnapshot("warnings"); 295 | 296 | resolve(); 297 | }); 298 | }); 299 | }); 300 | 301 | it("should run plugin against assets added later by plugins", async () => { 302 | const testJsonId = "./simple.json"; 303 | const compiler = getCompiler(testJsonId); 304 | 305 | new JsonMinimizerPlugin().apply(compiler); 306 | new EmitNewAsset({ name: "newFile.json" }).apply(compiler); 307 | 308 | const stats = await compile(compiler); 309 | 310 | expect(readAssets(compiler, stats, /\.json$/i)).toMatchSnapshot("assets"); 311 | expect(getErrors(stats)).toMatchSnapshot("errors"); 312 | expect(getWarnings(stats)).toMatchSnapshot("warnings"); 313 | }); 314 | }); 315 | -------------------------------------------------------------------------------- /test/__snapshots__/JsonMinimizerPlugin.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`JsonMinimizerPlugin should emit error when an empty file: errors 1`] = ` 4 | [ 5 | "Error: "empty.json" in "/test/fixtures" from Json Minimizer: 6 | SyntaxError: Unexpected end of JSON input", 7 | ] 8 | `; 9 | 10 | exports[`JsonMinimizerPlugin should emit error when an empty file: warnings 1`] = `[]`; 11 | 12 | exports[`JsonMinimizerPlugin should emit error when broken json syntax: warnings 1`] = `[]`; 13 | 14 | exports[`JsonMinimizerPlugin should run plugin against assets added later by plugins: assets 1`] = ` 15 | { 16 | "newFile.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true}", 17 | "simple.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 18 | } 19 | `; 20 | 21 | exports[`JsonMinimizerPlugin should run plugin against assets added later by plugins: errors 1`] = `[]`; 22 | 23 | exports[`JsonMinimizerPlugin should run plugin against assets added later by plugins: warnings 1`] = `[]`; 24 | 25 | exports[`JsonMinimizerPlugin should work (without options): assets 1`] = ` 26 | { 27 | "simple.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 28 | } 29 | `; 30 | 31 | exports[`JsonMinimizerPlugin should work (without options): errors 1`] = `[]`; 32 | 33 | exports[`JsonMinimizerPlugin should work (without options): warnings 1`] = `[]`; 34 | 35 | exports[`JsonMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": assets 1`] = ` 36 | { 37 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 38 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 39 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 40 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 41 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 42 | } 43 | `; 44 | 45 | exports[`JsonMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": errors 1`] = `[]`; 46 | 47 | exports[`JsonMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": errors 2`] = `[]`; 48 | 49 | exports[`JsonMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": result 1`] = ` 50 | { 51 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 52 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 53 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 54 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 55 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 56 | } 57 | `; 58 | 59 | exports[`JsonMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": warnings 1`] = `[]`; 60 | 61 | exports[`JsonMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": warnings 2`] = `[]`; 62 | 63 | exports[`JsonMinimizerPlugin should work and use cache by default in "development" mode: assets 1`] = ` 64 | { 65 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 66 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 67 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 68 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 69 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 70 | } 71 | `; 72 | 73 | exports[`JsonMinimizerPlugin should work and use cache by default in "development" mode: errors 1`] = `[]`; 74 | 75 | exports[`JsonMinimizerPlugin should work and use cache by default in "development" mode: errors 2`] = `[]`; 76 | 77 | exports[`JsonMinimizerPlugin should work and use cache by default in "development" mode: result 1`] = ` 78 | { 79 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 80 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 81 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 82 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 83 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 84 | } 85 | `; 86 | 87 | exports[`JsonMinimizerPlugin should work and use cache by default in "development" mode: warnings 1`] = `[]`; 88 | 89 | exports[`JsonMinimizerPlugin should work and use cache by default in "development" mode: warnings 2`] = `[]`; 90 | 91 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: assets 1`] = ` 92 | { 93 | "cache-1.json": "{"modified":true}", 94 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 95 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 96 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 97 | "cache.json": "{"modified":true}", 98 | } 99 | `; 100 | 101 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: errors 1`] = `[]`; 102 | 103 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: errors 2`] = `[]`; 104 | 105 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: result 1`] = ` 106 | { 107 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 108 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 109 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 110 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 111 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 112 | } 113 | `; 114 | 115 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 1`] = `[]`; 116 | 117 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 2`] = `[]`; 118 | 119 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true": assets 1`] = ` 120 | { 121 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 122 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 123 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 124 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 125 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 126 | } 127 | `; 128 | 129 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true": errors 1`] = `[]`; 130 | 131 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true": errors 2`] = `[]`; 132 | 133 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true": result 1`] = ` 134 | { 135 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 136 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 137 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 138 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 139 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 140 | } 141 | `; 142 | 143 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true": warnings 1`] = `[]`; 144 | 145 | exports[`JsonMinimizerPlugin should work and use memory cache when the "cache" option is "true": warnings 2`] = `[]`; 146 | 147 | exports[`JsonMinimizerPlugin should work and use memory cache: assets 1`] = ` 148 | { 149 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 150 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 151 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 152 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 153 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 154 | } 155 | `; 156 | 157 | exports[`JsonMinimizerPlugin should work and use memory cache: errors 1`] = `[]`; 158 | 159 | exports[`JsonMinimizerPlugin should work and use memory cache: errors 2`] = `[]`; 160 | 161 | exports[`JsonMinimizerPlugin should work and use memory cache: result 1`] = ` 162 | { 163 | "cache-1.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 164 | "cache-2.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 165 | "cache-3.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 166 | "cache-4.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 167 | "cache.json": "{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}", 168 | } 169 | `; 170 | 171 | exports[`JsonMinimizerPlugin should work and use memory cache: warnings 1`] = `[]`; 172 | 173 | exports[`JsonMinimizerPlugin should work and use memory cache: warnings 2`] = `[]`; 174 | 175 | exports[`JsonMinimizerPlugin should work with array: assets 1`] = ` 176 | { 177 | "array.json": "[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]", 178 | } 179 | `; 180 | 181 | exports[`JsonMinimizerPlugin should work with array: errors 1`] = `[]`; 182 | 183 | exports[`JsonMinimizerPlugin should work with array: warnings 1`] = `[]`; 184 | 185 | exports[`JsonMinimizerPlugin should work with child compilation: assets 1`] = ` 186 | { 187 | "simple.json": "{"x":5}", 188 | } 189 | `; 190 | 191 | exports[`JsonMinimizerPlugin should work with child compilation: errors 1`] = `[]`; 192 | 193 | exports[`JsonMinimizerPlugin should work with child compilation: warnings 1`] = `[]`; 194 | 195 | exports[`JsonMinimizerPlugin should work without files: assets 1`] = ` 196 | { 197 | "simple.json": "{ 198 | "squadName": "Super hero squad", 199 | "homeTown": "Metro City", 200 | "formed": 2016, 201 | "secretBase": "Super tower", 202 | "active": true, 203 | "members": [ 204 | { 205 | "name": "Molecule Man", 206 | "age": 29, 207 | "secretIdentity": "Dan Jukes", 208 | "powers": [ 209 | "Radiation resistance", 210 | "Turning tiny", 211 | "Radiation blast" 212 | ] 213 | }, 214 | { 215 | "name": "Madame Uppercut", 216 | "age": 39, 217 | "secretIdentity": "Jane Wilson", 218 | "powers": [ 219 | "Million tonne punch", 220 | "Damage resistance", 221 | "Superhuman reflexes" 222 | ] 223 | }, 224 | { 225 | "name": "Eternal Flame", 226 | "age": 1000000, 227 | "secretIdentity": "Unknown", 228 | "powers": [ 229 | "Immortality", 230 | "Heat Immunity", 231 | "Inferno", 232 | "Teleportation", 233 | "Interdimensional travel" 234 | ] 235 | } 236 | ] 237 | } 238 | ", 239 | } 240 | `; 241 | 242 | exports[`JsonMinimizerPlugin should work without files: errors 1`] = `[]`; 243 | 244 | exports[`JsonMinimizerPlugin should work without files: warnings 1`] = `[]`; 245 | --------------------------------------------------------------------------------