├── .cspell.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github
├── CODEOWNERS
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── BUG.md
│ ├── DOCS.md
│ ├── FEATURE.md
│ ├── MODIFICATION.md
│ └── SUPPORT.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── dependency-review.yml
│ └── nodejs.yml
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── babel.config.js
├── commitlint.config.js
├── jest.config.js
├── lint-staged.config.js
├── package-lock.json
├── package.json
├── setupTest.js
├── src
├── index.js
├── minify.js
├── options.json
└── utils.js
├── test
├── CssMinimizerPlugin.test.js
├── __snapshots__
│ ├── CssMinimizerPlugin.test.js.snap
│ ├── cache-option.test.js.snap
│ ├── exclude-option.test.js.snap
│ ├── include-option.test.js.snap
│ ├── minify-option.test.js.snap
│ ├── minimizerOptions-option.test.js.snap
│ ├── parallel-option.test.js.snap
│ ├── sourceMap-option.test.js.snap
│ ├── test-option.test.js.snap
│ ├── validate-options.test.js.snap
│ ├── warningsFilter-option.test.js.snap
│ └── worker.test.js.snap
├── cache-option.test.js
├── exclude-option.test.js
├── fixtures
│ ├── cache-1.js
│ ├── cache-2.js
│ ├── cache-3.js
│ ├── cache-4.js
│ ├── cache.js
│ ├── entry.js
│ ├── excluded1.js
│ ├── excluded2.js
│ ├── foo.css
│ ├── included1.js
│ ├── included2.js
│ ├── minimizerOptions
│ │ ├── discardComments.css
│ │ ├── discardEmpty.css
│ │ ├── mergeRules.css
│ │ └── order.css
│ ├── nesting.css
│ ├── simple-async.js
│ ├── simple-emit-2.js
│ ├── simple-emit.js
│ ├── simple.js
│ ├── sourcemap
│ │ ├── bar.css
│ │ ├── bar.scss
│ │ ├── foo.css
│ │ └── foo.scss
│ ├── sss
│ │ └── index.sss
│ ├── sugarss.js
│ ├── test
│ │ ├── bar1.css
│ │ ├── bar2.css
│ │ ├── error.css
│ │ └── foo.css
│ └── wrong-calc.css
├── helpers
│ ├── EmitNewAsset.js
│ ├── ModifyExistingAsset.js
│ ├── compile.js
│ ├── emitAssetInChildCompilationLoader.js
│ ├── emitAssetLoader.js
│ ├── emitAssetLoader2.js
│ ├── getCompiler.js
│ ├── getErrors.js
│ ├── getWarnings.js
│ ├── index.js
│ ├── normalizeErrors.js
│ ├── readAsset.js
│ └── readAssets.js
├── include-option.test.js
├── minify-option.test.js
├── minimizerOptions-option.test.js
├── parallel-option.test.js
├── sourceMap-option.test.js
├── test-option.test.js
├── validate-options.test.js
├── warningsFilter-option.test.js
└── worker.test.js
├── tsconfig.json
└── types
├── index.d.ts
├── minify.d.ts
└── utils.d.ts
/.cspell.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2",
3 | "language": "en,en-gb",
4 | "words": [
5 | "esbuild",
6 | "csso",
7 | "cssnano",
8 | "Stringifier",
9 | "stringifier",
10 | "KAAK",
11 | "UAAU",
12 | "OAAO",
13 | "colormin",
14 | "sugarss",
15 | "lightningcss",
16 | "minifiers",
17 | "pathinfo",
18 | "memfs",
19 | "colortable",
20 | "fullhash",
21 | "chunkhash",
22 | "OAAOA",
23 | "SAAUE",
24 | "IAAM",
25 | "IAAI",
26 | "IAAID",
27 | "OAAOC",
28 | "SAAUA",
29 | "CAAC",
30 | "minifier",
31 | "sourcemaps",
32 | "processoptions",
33 | "nosources",
34 | "pathinfo",
35 | "commitlint",
36 | "memfs",
37 | "colortable",
38 | "wagoid",
39 | "autocrlf",
40 | "codecov",
41 | "jridgewell"
42 | ],
43 |
44 | "ignorePaths": [
45 | "CHANGELOG.md",
46 | "package.json",
47 | "dist/**",
48 | "**/__snapshots__/**",
49 | "package-lock.json",
50 | "*.pack",
51 | "node_modules",
52 | "coverage",
53 | "*.log"
54 | ]
55 | }
56 |
--------------------------------------------------------------------------------
/.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
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /dist
3 | /node_modules
4 | /test/fixtures
5 | /types/**/*
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ["@webpack-contrib/eslint-config-webpack", "prettier"],
4 | rules: {
5 | "import/no-namespace": "off",
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | bin/* eol=lf
3 | yarn.lock -diff
4 | package-lock.json -diff
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # These are the default owners for everything in
2 | # webpack-contrib
3 | @webpack-contrib/org-maintainers
4 |
5 | # Add repository specific users / groups
6 | # below here for libs that are not maintained by the org.
7 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing in @webpack-contrib
2 |
3 | We'd always love contributions to further improve the webpack / webpack-contrib ecosystem!
4 | Here are the guidelines we'd like you to follow:
5 |
6 | - [Questions and Problems](#question)
7 | - [Issues and Bugs](#issue)
8 | - [Feature Requests](#feature)
9 | - [Pull Request Submission Guidelines](#submit-pr)
10 | - [Commit Message Conventions](#commit)
11 |
12 | ## Got a Question or Problem?
13 |
14 | Please submit support requests and questions to StackOverflow using the tag [[webpack]](http://stackoverflow.com/tags/webpack).
15 | StackOverflow is better suited for this kind of support though you may also inquire in [Webpack Gitter](https://gitter.im/webpack/webpack).
16 | The issue tracker is for bug reports and feature discussions.
17 |
18 | ## Found an Issue or Bug?
19 |
20 | Before you submit an issue, please search the issue tracker, an issue for your problem may already exist, and the discussion might inform you of workarounds readily available.
21 |
22 | We want to fix all the issues as soon as possible, but before fixing a bug, we need to reproduce and confirm it. In order to reproduce bugs, we ask that you provide a minimal reproduction scenario (GitHub repo or failing test case). Having a live, reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions like:
23 |
24 | - version of Webpack used
25 | - version of the loader / plugin you are creating a bug report for
26 | - the use-case that fails
27 |
28 | A minimal reproduce scenario allows us to quickly confirm a bug (or point out config problems) as well as confirm that we are fixing the right problem.
29 |
30 | We will be insisting on a minimal reproduction scenario in order to save the maintainers' time and ultimately be able to fix more bugs. We understand that sometimes it might be hard to extract essential bits of code from a larger codebase, but we really need to isolate the problem before we can fix it.
31 |
32 | nfortunately, we are unable to investigate or fix bugs without a minimal reproduction, so if we don't hear back from you, we may have to close an issue that doesn't have enough info to be reproduced.
33 |
34 | ## Feature Requests?
35 |
36 | You can _request_ a new feature by creating an issue on GitHub.
37 |
38 | If you would like to _implement_ a new feature yourself, please **first submit an issue** with a proposal to ensure the idea aligns with the goals of the project.
39 |
40 | ## Pull Request Submission Guidelines
41 |
42 | Before you submit your Pull Request (PR) consider the following guidelines:
43 |
44 | - Search GitHub for an open or closed PR related to your submission to avoid duplicating effort.
45 | - Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit). This is important because release notes are automatically generated from these messages.
46 | - Complete the `Pull Request Template`. Pull requests that ignore the template will not be reviewed.
47 | - Please sign the `Contributor License Agreement (CLA)` when you open your pull request. We cannot accept your contribution without it. Be sure to sign using the primary email address associated with your local and GitHub account.
48 |
49 | ## Webpack Contrib Commit Conventions
50 |
51 | Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
52 | format that includes a **type**, a **scope** and a **subject**:
53 |
54 | ```
55 | ():
56 |
57 |
58 |
59 |
60 | ```
61 |
62 | The **header** is mandatory and the **scope** of the header is optional.
63 |
64 | No line in the commit message should exceed 100 characters! This makes the message easier to read on GitHub as well as in various git tools.
65 |
66 | The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
67 |
68 | Examples:
69 |
70 | ```
71 | docs(readme): update install instructions
72 | ```
73 |
74 | ```
75 | fix: refer to the `entrypoint` instead of the first `module`
76 | ```
77 |
78 | ### Revert
79 |
80 | If the commit reverts a previous commit, it should begin with `revert:`, followed by the header of the reverted commit.
81 | In the body it should say: `This reverts commit .`, where the hash is the SHA of the commit being reverted.
82 |
83 | ### Type
84 |
85 | Must be one of the following commit types:
86 |
87 | - **build**: Changes that affect the build system or external dependencies (example scopes: babel, npm)
88 | - **chore**: Changes that fall outside of build / docs that do not effect source code (example scopes: package, defaults)
89 | - **ci**: Changes to our CI configuration files and scripts (example scopes: circleci, travis)
90 | - **docs**: Documentation only changes (example scopes: readme, changelog)
91 | - **feat**: A new feature
92 | - **fix**: A bug fix
93 | - **perf**: A code change that improves performance
94 | - **refactor**: A code change that neither fixes a bug nor adds a feature
95 | - **revert**: Used when reverting a committed change
96 | - **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons)
97 | - **test**: Addition of or updates to Jest tests
98 |
99 | ### Scope
100 |
101 | The scope is subjective & depends on the `type` see above. A good example of a scope would be a change to a particular class or module.
102 |
103 | ### Subject
104 |
105 | The subject contains a succinct description of the change:
106 |
107 | - use the imperative, present tense: "change" not "changed" or "changes"
108 | - don't capitalize the first letter
109 | - no dot (.) at the end
110 |
111 | ### Body
112 |
113 | Just as in the **subject**, use the imperative, present tense: "change" not "changed" or "changes".
114 | The body should include the motivation for the change and contrast it with previous behavior.
115 |
116 | ### Footer
117 |
118 | The footer should include any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit **Closes**.
119 |
120 | **Breaking Changes** must start with the word `BREAKING CHANGE:` followed by a space or two new lines. The rest of the breaking change details should be provided after this.
121 |
122 | Example
123 |
124 | ```
125 | BREAKING CHANGE: Updates to `Chunk.mapModules`.
126 |
127 | This release is not backwards compatible with `Webpack 2.x` due to breaking changes in webpack/webpack#4764
128 | Migration: see webpack/webpack#5225
129 |
130 | ```
131 |
132 | ## Testing Your Pull Request
133 |
134 | You may need to test your changes in a real-world project or a dependent module. Thankfully, GitHub provides a means to do this. To add a dependency to the `package.json` of such a project, use the following syntax:
135 |
136 | ```json
137 | {
138 | "devDependencies": {
139 | "css-minimizer-webpack-plugin": "webpack-contrib/css-minimizer-webpack-plugin#{id}/head"
140 | }
141 | }
142 | ```
143 |
144 | Where `{id}` is the # ID of your Pull Request.
145 |
146 | ## Contributor License Agreement
147 |
148 | When submitting your contribution, a CLA (Contributor License Agreement) bot will verify whether you have signed the [CLA](https://easycla.lfx.linuxfoundation.org/#/?version=2).
149 | If it is your first time, it will link you to the right place to sign it.
150 | However, if the email used in your commits doesn’t match the email associated with your GitHub account, the CLA bot won’t accept your contribution.
151 |
152 | Run `git config user.email` to see your Git email, and verify it with [your GitHub email](https://github.com/settings/emails).
153 |
154 | ## Thanks
155 |
156 | For your interest, time, understanding, and for following this simple guide.
157 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: webpack
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐛 Bug Report
3 | about: Something went awry and you'd like to tell us about it.
4 | ---
5 |
6 |
7 |
8 |
9 | ### Bug report
10 |
11 |
12 |
13 |
14 |
15 |
16 | ### Actual Behavior
17 |
18 |
19 |
20 | ### Expected Behavior
21 |
22 |
23 |
24 |
25 | ### How Do We Reproduce?
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ### Please paste the results of `npx webpack-cli info` here, and mention other relevant information.
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/DOCS.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 📚 Documentation
3 | about: Are the docs lacking or missing something? Do they need some new 🔥 hotness? Tell us here.
4 | ---
5 |
6 |
7 |
8 |
9 | Documentation is:
10 |
11 |
12 |
13 | - [ ] Missing
14 | - [ ] Needed
15 | - [ ] Confusing
16 | - [ ] Not Sure?
17 |
18 | ### Please Explain in Detail...
19 |
20 |
21 |
22 |
23 |
24 |
25 | ### Your Proposal for Changes
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/FEATURE.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: ✨ Feature Request
3 | about: Suggest an idea for this project
4 | ---
5 |
6 |
7 |
8 |
9 | ### Feature Proposal
10 |
11 |
12 |
13 |
14 |
15 |
16 | ### Feature Use Case
17 |
18 |
19 |
20 | ### Please paste the results of `npx webpack-cli info` here, and mention other relevant information.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/MODIFICATION.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🔧 Modification Request
3 | about: Want something to work differently? Have an alternative approach? This is the template for you.
4 | ---
5 |
6 |
7 |
8 |
9 | ### Modification Proposal
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ### Expected Behavior / Situation
18 |
19 |
20 |
21 | ### Actual Behavior / Situation
22 |
23 |
24 |
25 | ### Please paste the results of `npx webpack-cli info` here, and mention other relevant information.
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/SUPPORT.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🆘 Support, Help, and Advice
3 | about: 👉🏽 Need support, help, or advice? Don't open an issue! Head to https://github.com/webpack/webpack/discussions or StackOverflow
4 | ---
5 |
6 | Hey there! 👋
7 |
8 | If you need support, help, or advice then this is not the right place to ask.
9 |
10 | Please visit one of the following instead:
11 |
12 | - [GitHub Discussions](https://github.com/webpack/webpack/discussions)
13 | - [StackOverflow](https://stackoverflow.com/questions/tagged/webpack)
14 |
15 | Thanks for understanding!
16 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 |
11 | This PR contains a:
12 |
13 | - [ ] **bugfix**
14 | - [ ] new **feature**
15 | - [ ] **code refactor**
16 | - [ ] **test update**
17 | - [ ] **typo fix**
18 | - [ ] **metadata update**
19 |
20 | ### Motivation / Use-Case
21 |
22 |
27 |
28 | ### Breaking Changes
29 |
30 |
34 |
35 | ### Additional Info
36 |
--------------------------------------------------------------------------------
/.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@v4
13 | - name: "Dependency Review"
14 | uses: actions/dependency-review-action@v4
15 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | name: css-minimizer-webpack-plugin
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - next
8 | pull_request:
9 | branches:
10 | - master
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@v4
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@v4
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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | coverage
3 | .vscode
4 | logs
5 | *.log
6 | npm-debug.log*
7 | .cspellcache
8 | .eslintcache
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 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | commitlint --edit $1
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | lint-staged
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /dist
3 | /node_modules
4 | /test/fixtures
5 | CHANGELOG.md
--------------------------------------------------------------------------------
/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 | ### [7.0.2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v7.0.1...v7.0.2) (2025-03-06)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * better types ([9d009b3](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/9d009b366a6f45b44d3120bda8450c28ceee6427))
11 |
12 | ### [7.0.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v7.0.0...v7.0.1) (2025-03-06)
13 |
14 |
15 | ### Bug Fixes
16 |
17 | * better support worker threads ([eeaa5e1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/eeaa5e16861614c54568db35c17a2e8cad0d3c26))
18 | * use os.availableParallelism() for parallelism when it is available ([b07feeb](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/b07feeb3e46e6a3d6ab9a32ca19711559b3afb3a))
19 |
20 | ## [7.0.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v6.0.0...v7.0.0) (2024-05-07)
21 |
22 |
23 | ### ⚠ BREAKING CHANGES
24 |
25 | * update cssnano to 7.0 ([#263](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/263)) ([a252ce9](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/a252ce91aad42181af0e4c71f1a00990c1efeeeb))
26 |
27 | ## [6.0.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v5.0.1...v6.0.0) (2024-01-17)
28 |
29 |
30 | ### ⚠ BREAKING CHANGES
31 |
32 | * minimum supported Node.js version is `18.12.0` ([#252](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/252)) ([f7f74c0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/f7f74c02c8a53e517d9942807c198d1daff0c4b5))
33 |
34 | ### [5.0.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v5.0.0...v5.0.1) (2023-06-13)
35 |
36 |
37 | ### Bug Fixes
38 |
39 | * improve perf ([#235](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/235)) ([959eb89](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/959eb89aa1e37df88d2decbe6f40c096f10a3745))
40 |
41 | ## [5.0.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v4.2.2...v5.0.0) (2023-03-27)
42 |
43 |
44 | ### ⚠ BREAKING CHANGES
45 |
46 | * update `cssnano` to v6 (migration guide - https://github.com/cssnano/cssnano/releases/tag/cssnano%406.0.0) (#224)
47 |
48 | ### Features
49 |
50 | * update `cssnano` to v6 ([#224](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/224)) ([cfcae0c](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/cfcae0c9e2b7afd740774104a8e5eb675fe984db))
51 |
52 | ### [4.2.2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v4.2.1...v4.2.2) (2022-10-13)
53 |
54 |
55 | ### Bug Fixes
56 |
57 | * handle `swc` errors ([#202](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/202)) ([b1ce195](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/b1ce195a0de508217ea1a91d7f8e2683e77b495a))
58 |
59 | ### [4.2.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v4.2.0...v4.2.1) (2022-10-06)
60 |
61 |
62 | ### Bug Fixes
63 |
64 | * crash ([#200](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/200)) ([c50b2b2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/c50b2b25348a78a6bfaff248e0fb356a70a4241c))
65 |
66 | ## [4.2.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v4.1.0...v4.2.0) (2022-09-29)
67 |
68 |
69 | ### Features
70 |
71 | * added `swc` minimizer ([#197](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/197)) ([5461421](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/546142104cb30e4711ba800170961822de7d0097))
72 |
73 | ## [4.1.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v4.0.0...v4.1.0) (2022-09-09)
74 |
75 |
76 | ### Features
77 |
78 | * added `lightningcss` support ([#192](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/192)) ([04a3347](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/04a3347610a0044116bfebfd3f3be50d3ada4e04))
79 |
80 | ## [4.0.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.4.1...v4.0.0) (2022-05-18)
81 |
82 |
83 | ### ⚠ BREAKING CHANGES
84 |
85 | * minimum supported `Node.js` version is `14.15.0`
86 |
87 | ### [3.4.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.4.0...v3.4.1) (2022-01-18)
88 |
89 |
90 | ### Bug Fixes
91 |
92 | * types ([9c8b0f3](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/9c8b0f35cc6fc8816c387c48c535d71891d8aa65))
93 |
94 | ## [3.4.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.3.1...v3.4.0) (2022-01-18)
95 |
96 |
97 | ### Features
98 |
99 | * added `@parcel/css` support ([#154](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/154)) ([5e5fe51](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/5e5fe512c7209f0ad4c7f9c55f47cf9763adfc74))
100 |
101 | ### [3.3.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.3.0...v3.3.1) (2021-12-21)
102 |
103 |
104 | ### Bug Fixes
105 |
106 | * cssnano types ([#147](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/147)) ([a51026e](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/a51026e3b948fa14d2334d823b3bbb6ea482c57b))
107 |
108 | ## [3.3.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.2.0...v3.3.0) (2021-12-16)
109 |
110 |
111 | ### Features
112 |
113 | * removed cjs wrapper and generated types in commonjs format (`export =` and `namespaces` used in types), now you can directly use exported types ([3262a9a](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/3262a9aee2c89e6aed00c4f76443e0d1e07489f0))
114 |
115 | ## [3.2.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.1.4...v3.2.0) (2021-11-23)
116 |
117 |
118 | ### Features
119 |
120 | * added types ([#142](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/142)) ([fb91610](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/fb91610730166b8fb4fb09cee5da781f0ec98e70))
121 |
122 | ### [3.1.4](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.1.3...v3.1.4) (2021-11-17)
123 |
124 |
125 | ### Chore
126 |
127 | * update `schema-utils` package to `4.0.0` version
128 |
129 | ### [3.1.3](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.1.2...v3.1.3) (2021-11-10)
130 |
131 |
132 | ### Bug Fixes
133 |
134 | * source map generation for `cssnano` and `clean-css` ([#135](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/135)) ([a9dd43e](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/a9dd43e1a7284bb713e19eac6fa3f3724fb9d48b))
135 |
136 | ### [3.1.2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.1.1...v3.1.2) (2021-11-08)
137 |
138 |
139 | ### Bug Fixes
140 |
141 | * handle `esbuild` warnings ([f427f41](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/f427f41d319b340262c9b5061cf5427bdf5a5f78))
142 |
143 | ### [3.1.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.1.0...v3.1.1) (2021-10-05)
144 |
145 |
146 | ### Bug Fixes
147 |
148 | * minified result can be empty ([#127](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/127)) ([0a8ad71](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/0a8ad71fa0da86c5f76381f13ddf013db02a60ea))
149 |
150 | ## [3.1.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.0.2...v3.1.0) (2021-10-04)
151 |
152 |
153 | ### Features
154 |
155 | * added `esbuild` minimizer ([#122](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/122)) ([987d454](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/987d45402af81d88fbd1489021f8d14e5ff26a74))
156 | * allow returning errors from custom minimize function ([#121](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/121)) ([c9a11b2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/c9a11b2349d24206bc03cf3670f50a822ef7a52b))
157 | * output documentation links on errors ([4e8afba](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/4e8afbae5c89b0fe52b83b69fb2c5ab8a6382750))
158 |
159 |
160 | ### Bug Fixes
161 |
162 | * source map generation for multiple `minify` functions ([b736099](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/b7360993a50a4d998bb92f0a3d491030452fcb0b))
163 |
164 | ### [3.0.2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.0.1...v3.0.2) (2021-06-25)
165 |
166 | ### Chore
167 |
168 | * update `serialize-javascript`
169 |
170 | ### [3.0.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v3.0.0...v3.0.1) (2021-05-31)
171 |
172 | ### Chore
173 |
174 | * update `jest-worker`
175 |
176 | ## [3.0.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v2.0.0...v3.0.0) (2021-05-12)
177 |
178 |
179 | ### ⚠ BREAKING CHANGES
180 |
181 | * minimum supported `Node.js` version is `12.13.0`
182 |
183 | ## [2.0.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.3.0...v2.0.0) (2021-04-10)
184 |
185 |
186 | ### ⚠ BREAKING CHANGES
187 |
188 | * update `cssnano` to `5.0.0` version
189 | * drop `webpack` v4 support,
190 | * removed the `cache` option (respect the [`cache`](https://webpack.js.org/configuration/other-options/#cache) option from `webpack`)
191 | * removed the `cacheKeys` option respect the [`cache`](https://webpack.js.org/configuration/other-options/#cache) option from `webpack`)
192 | * removed the sourceMap option (respect the [`devtool`](https://webpack.js.org/configuration/devtool/) option from `webpack`)
193 |
194 | ### Features
195 |
196 | * added defaults functions for `clean-css` and `csso`, please look at [here](https://github.com/webpack-contrib/css-minimizer-webpack-plugin#minify) ([5211eed](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/5211eed3c816212a30715ebf0798393c886343d0))
197 | * added the ability to pass an array of functions to the minify ([91f9977](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/91f9977e9fdd1447cb45bc6f5d4b56fe7c26fb04))
198 | * update `cssnano` to `5.0.0` version ([4d2a8fd](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/4d2a8fd275ab17f6d98e4581b6c2adf09c73c91c))
199 |
200 | ## [1.3.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.2.0...v1.3.0) (2021-03-15)
201 |
202 |
203 | ### Features
204 |
205 | * added support `processorOptions` for `cssnano` ([8865423](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/886542375dc37411e271d151b7060be574fc5898))
206 |
207 | ## [1.2.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.1.5...v1.2.0) (2021-01-08)
208 |
209 |
210 | ### Features
211 |
212 | * optimize CSS assets added later by plugins (webpack@5 only) ([#47](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/47)) ([bdb3f52](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/bdb3f524289a2c131e2ec3728cf10b4c9a0010c7))
213 |
214 |
215 | ### Bug Fixes
216 |
217 | * crash with source maps when the `parallel` option is `false` ([#53](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/53)) ([4fe95f9](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/4fe95f9b63764d06ffc4e6d6d77a45ba2dd1b76b))
218 |
219 | ### [1.1.5](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.1.4...v1.1.5) (2020-10-07)
220 |
221 | ### Chore
222 |
223 | * update `schema-utils`
224 |
225 | ### [1.1.4](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.1.3...v1.1.4) (2020-09-18)
226 |
227 |
228 | ### Bug Fixes
229 |
230 | * weak cache
231 | * source map generation
232 | * cache warnings between builds
233 |
234 | ### [1.1.3](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.1.2...v1.1.3) (2020-09-03)
235 |
236 |
237 | ### Bug Fixes
238 |
239 | * do not crash on the `minify` option ([fd9abac](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/fd9abac59dc82561ef1db603165526caba6e9abe))
240 |
241 | ### [1.1.2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.1.1...v1.1.2) (2020-08-24)
242 |
243 |
244 | ### Bug Fixes
245 |
246 | * compatibility with webpack 5 ([6232829](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/62328298d6a81f31e773d11ced8811ee41cd0470))
247 |
248 | ### [1.1.1](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.1.0...v1.1.1) (2020-08-10)
249 |
250 |
251 | ### Bug Fixes
252 |
253 | * compatibility with `10.13` version of `Node.js` ([d38ea79](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/d38ea793bc2cefc6289d2fe8f2e5df8c31e487e0))
254 |
255 | ## [1.1.0](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/compare/v1.0.0...v1.1.0) (2020-08-04)
256 |
257 |
258 | ### Features
259 |
260 | * show minimized assets in stats for webpack@5 ([#19](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/19)) ([cb038b9](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/cb038b91b15e934a56c260635506df4f02efd747))
261 |
262 |
263 | ### Bug Fixes
264 |
265 | * compatibility cache feature with webpack@5 ([#16](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/16)) ([997e00f](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/997e00f66298219dccfdff8c01c71bebc973df49))
266 | * skip double compression for child compilation ([#18](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues/18)) ([ffc71c2](https://github.com/webpack-contrib/css-minimizer-webpack-plugin/commit/ffc71c2c5269ba12c794be87c3257390fdd9c926))
267 |
268 | ## 1.0.0 - 2020-08-01
269 |
270 | Initial release
271 |
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: "node",
3 | setupFilesAfterEnv: ["/setupTest.js"],
4 | };
5 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "css-minimizer-webpack-plugin",
3 | "version": "7.0.2",
4 | "description": "CSS minimizer (minifier) plugin for Webpack",
5 | "license": "MIT",
6 | "repository": "webpack-contrib/css-minimizer-webpack-plugin",
7 | "author": "Loann Neveu",
8 | "homepage": "https://github.com/webpack-contrib/css-minimizer-webpack-plugin",
9 | "bugs": "https://github.com/webpack-contrib/css-minimizer-webpack-plugin/issues",
10 | "funding": {
11 | "type": "opencollective",
12 | "url": "https://opencollective.com/webpack"
13 | },
14 | "main": "dist/index.js",
15 | "types": "types/index.d.ts",
16 | "engines": {
17 | "node": ">= 18.12.0"
18 | },
19 | "scripts": {
20 | "start": "npm run build -- -w",
21 | "clean": "del-cli dist",
22 | "prebuild": "npm run clean types",
23 | "build:types": "tsc --declaration --emitDeclarationOnly --outDir types && prettier \"types/**/*.ts\" --write",
24 | "build:code": "cross-env NODE_ENV=production babel src -d dist --copy-files",
25 | "build": "npm-run-all -p \"build:**\"",
26 | "commitlint": "commitlint --from=master",
27 | "security": "npm audit",
28 | "lint:prettier": "prettier --cache --list-different .",
29 | "lint:js": "eslint --cache .",
30 | "lint:spelling": "cspell --cache --no-must-find-files --quiet \"**/*.*\"",
31 | "lint:types": "tsc --pretty --noEmit",
32 | "lint": "npm-run-all -l -p \"lint:**\"",
33 | "fix:js": "npm run lint:js -- --fix",
34 | "fix:prettier": "npm run lint:prettier -- --write",
35 | "fix": "npm-run-all -l fix:js fix:prettier",
36 | "test:only": "cross-env NODE_ENV=test NODE_OPTIONS=\"--experimental-vm-modules\" jest",
37 | "test:watch": "npm run test:only -- --watch",
38 | "test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
39 | "pretest": "npm run lint",
40 | "test": "npm run test:coverage",
41 | "prepare": "husky && npm run build",
42 | "release": "standard-version"
43 | },
44 | "files": [
45 | "dist",
46 | "types"
47 | ],
48 | "peerDependencies": {
49 | "webpack": "^5.0.0"
50 | },
51 | "peerDependenciesMeta": {
52 | "clean-css": {
53 | "optional": true
54 | },
55 | "csso": {
56 | "optional": true
57 | },
58 | "esbuild": {
59 | "optional": true
60 | },
61 | "@parcel/css": {
62 | "optional": true
63 | },
64 | "lightningcss": {
65 | "optional": true
66 | },
67 | "@swc/css": {
68 | "optional": true
69 | }
70 | },
71 | "dependencies": {
72 | "@jridgewell/trace-mapping": "^0.3.25",
73 | "cssnano": "^7.0.4",
74 | "jest-worker": "^29.7.0",
75 | "postcss": "^8.4.40",
76 | "schema-utils": "^4.2.0",
77 | "serialize-javascript": "^6.0.2"
78 | },
79 | "devDependencies": {
80 | "@babel/cli": "^7.24.8",
81 | "@babel/core": "^7.25.2",
82 | "@babel/preset-env": "^7.25.3",
83 | "@commitlint/cli": "^19.3.0",
84 | "@commitlint/config-conventional": "^19.2.2",
85 | "@parcel/css": "^1.8.3",
86 | "@swc/css": "^0.0.28",
87 | "@types/clean-css": "^4.2.11",
88 | "@types/csso": "^5.0.4",
89 | "@types/node": "^20.14.9",
90 | "@types/serialize-javascript": "^5.0.4",
91 | "@webpack-contrib/eslint-config-webpack": "^3.0.0",
92 | "babel-jest": "^29.7.0",
93 | "clean-css": "^5.3.3",
94 | "copy-webpack-plugin": "^9.1.0",
95 | "cross-env": "^7.0.3",
96 | "cspell": "^8.13.1",
97 | "css-loader": "^6.10.0",
98 | "cssnano-preset-simple": "^4.0.0",
99 | "csso": "^5.0.3",
100 | "del": "^6.1.0",
101 | "del-cli": "^5.1.0",
102 | "esbuild": "^0.25.0",
103 | "eslint": "^8.56.0",
104 | "eslint-config-prettier": "^9.1.0",
105 | "eslint-plugin-import": "^2.29.1",
106 | "husky": "^9.1.4",
107 | "jest": "^29.7.0",
108 | "lightningcss": "^1.25.1",
109 | "lint-staged": "^15.2.8",
110 | "memfs": "^4.11.1",
111 | "mini-css-extract-plugin": "^2.9.0",
112 | "npm-run-all": "^4.1.5",
113 | "prettier": "^3.3.3",
114 | "sass": "^1.77.8",
115 | "sass-loader": "^14.2.1",
116 | "standard-version": "^9.5.0",
117 | "sugarss": "^4.0.1",
118 | "typescript": "^5.5.4",
119 | "webpack": "^5.93.0"
120 | },
121 | "keywords": [
122 | "cssnano",
123 | "css",
124 | "csso",
125 | "clean-css",
126 | "swc",
127 | "esbuild",
128 | "webpack",
129 | "webpack-plugin",
130 | "minimize",
131 | "minimizer",
132 | "minify",
133 | "minifier",
134 | "optimize",
135 | "optimizer"
136 | ]
137 | }
138 |
--------------------------------------------------------------------------------
/setupTest.js:
--------------------------------------------------------------------------------
1 | jest.setTimeout(120000);
2 |
--------------------------------------------------------------------------------
/src/minify.js:
--------------------------------------------------------------------------------
1 | /** @typedef {import("./index.js").MinimizedResult} MinimizedResult */
2 | /** @typedef {import("./index.js").InternalResult} InternalResult */
3 |
4 | /**
5 | * @template T
6 | * @param {import("./index.js").InternalOptions} options
7 | * @returns {Promise}
8 | */
9 | async function minify(options) {
10 | const minifyFns = Array.isArray(options.minimizer.implementation)
11 | ? options.minimizer.implementation
12 | : [options.minimizer.implementation];
13 |
14 | /** @type {InternalResult} */
15 | const result = { outputs: [], warnings: [], errors: [] };
16 |
17 | let needSourceMap = false;
18 |
19 | for (let i = 0; i <= minifyFns.length - 1; i++) {
20 | const minifyFn = minifyFns[i];
21 | const minifyOptions = Array.isArray(options.minimizer.options)
22 | ? options.minimizer.options[i]
23 | : options.minimizer.options;
24 | const prevResult =
25 | result.outputs.length > 0
26 | ? result.outputs[result.outputs.length - 1]
27 | : { code: options.input, map: options.inputSourceMap };
28 | const { code, map } = prevResult;
29 | // eslint-disable-next-line no-await-in-loop
30 | const minifyResult = await minifyFn(
31 | { [options.name]: code },
32 | map,
33 | minifyOptions,
34 | );
35 |
36 | if (typeof minifyResult.code !== "string") {
37 | throw new Error(
38 | "minimizer function doesn't return the 'code' property or result is not a string value",
39 | );
40 | }
41 |
42 | if (minifyResult.map) {
43 | needSourceMap = true;
44 | }
45 |
46 | if (minifyResult.errors) {
47 | result.errors = result.errors.concat(minifyResult.errors);
48 | }
49 |
50 | if (minifyResult.warnings) {
51 | result.warnings = result.warnings.concat(minifyResult.warnings);
52 | }
53 |
54 | result.outputs.push({ code: minifyResult.code, map: minifyResult.map });
55 | }
56 |
57 | if (!needSourceMap) {
58 | result.outputs = [result.outputs[result.outputs.length - 1]];
59 | }
60 |
61 | return result;
62 | }
63 |
64 | /**
65 | * @param {string} options
66 | * @returns {Promise}
67 | */
68 | async function transform(options) {
69 | // 'use strict' => this === undefined (Clean Scope)
70 | // Safer for possible security issues, albeit not critical at all here
71 | // eslint-disable-next-line no-new-func, no-param-reassign
72 | const evaluatedOptions = new Function(
73 | "exports",
74 | "require",
75 | "module",
76 | "__filename",
77 | "__dirname",
78 | `'use strict'\nreturn ${options}`,
79 | )(exports, require, module, __filename, __dirname);
80 |
81 | return minify(evaluatedOptions);
82 | }
83 |
84 | module.exports = { minify, transform };
85 |
--------------------------------------------------------------------------------
/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 | "MinimizerOptions": {
36 | "additionalProperties": true,
37 | "type": "object"
38 | }
39 | },
40 | "title": "CssMinimizerWebpackPluginOptions",
41 | "type": "object",
42 | "properties": {
43 | "test": {
44 | "description": "Include all modules that pass test assertion.",
45 | "link": "https://github.com/webpack-contrib/css-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-contrib/css-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-contrib/css-minimizer-webpack-plugin/#exclude",
64 | "oneOf": [
65 | {
66 | "$ref": "#/definitions/Rules"
67 | }
68 | ]
69 | },
70 | "minimizerOptions": {
71 | "description": "Options for `cssMinimizerOptions`.",
72 | "link": "https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#minimizeroptions",
73 | "anyOf": [
74 | {
75 | "$ref": "#/definitions/MinimizerOptions"
76 | },
77 | {
78 | "type": "array",
79 | "minItems": 1,
80 | "items": {
81 | "$ref": "#/definitions/MinimizerOptions"
82 | }
83 | }
84 | ]
85 | },
86 | "parallel": {
87 | "description": "Use multi-process parallel running to improve the build speed.",
88 | "link": "https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#parallel",
89 | "anyOf": [
90 | {
91 | "type": "boolean"
92 | },
93 | {
94 | "type": "integer"
95 | }
96 | ]
97 | },
98 | "warningsFilter": {
99 | "description": "Allow to filter `css minimizer` warnings.",
100 | "link": "https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#warningsfilter",
101 | "instanceof": "Function"
102 | },
103 | "minify": {
104 | "description": "Allows you to override default minify function.",
105 | "link": "https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#minify",
106 | "anyOf": [
107 | {
108 | "instanceof": "Function"
109 | },
110 | {
111 | "type": "array",
112 | "minItems": 1,
113 | "items": {
114 | "instanceof": "Function"
115 | }
116 | }
117 | ]
118 | }
119 | },
120 | "additionalProperties": false
121 | }
122 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | /** @typedef {import("./index.js").Input} Input */
2 | /** @typedef {import("@jridgewell/trace-mapping").EncodedSourceMap} RawSourceMap */
3 | /** @typedef {import("./index.js").MinimizedResult} MinimizedResult */
4 | /** @typedef {import("./index.js").CustomOptions} CustomOptions */
5 | /** @typedef {import("postcss").ProcessOptions} ProcessOptions */
6 | /** @typedef {import("postcss").Postcss} Postcss */
7 |
8 | const notSettled = Symbol(`not-settled`);
9 |
10 | /**
11 | * @template T
12 | * @typedef {() => Promise} Task
13 | */
14 |
15 | /**
16 | * Run tasks with limited concurrency.
17 | * @template T
18 | * @param {number} limit - Limit of tasks that run at once.
19 | * @param {Task[]} tasks - List of tasks to run.
20 | * @returns {Promise} A promise that fulfills to an array of the results
21 | */
22 | function throttleAll(limit, tasks) {
23 | if (!Number.isInteger(limit) || limit < 1) {
24 | throw new TypeError(
25 | `Expected \`limit\` to be a finite number > 0, got \`${limit}\` (${typeof limit})`,
26 | );
27 | }
28 |
29 | if (
30 | !Array.isArray(tasks) ||
31 | !tasks.every((task) => typeof task === `function`)
32 | ) {
33 | throw new TypeError(
34 | `Expected \`tasks\` to be a list of functions returning a promise`,
35 | );
36 | }
37 |
38 | return new Promise((resolve, reject) => {
39 | const result = Array(tasks.length).fill(notSettled);
40 | const entries = tasks.entries();
41 | const next = () => {
42 | const { done, value } = entries.next();
43 |
44 | if (done) {
45 | const isLast = !result.includes(notSettled);
46 |
47 | if (isLast) resolve(result);
48 |
49 | return;
50 | }
51 |
52 | const [index, task] = value;
53 |
54 | /**
55 | * @param {T} x
56 | */
57 | const onFulfilled = (x) => {
58 | result[index] = x;
59 | next();
60 | };
61 |
62 | task().then(onFulfilled, reject);
63 | };
64 |
65 | Array(limit).fill(0).forEach(next);
66 | });
67 | }
68 |
69 | /* istanbul ignore next */
70 | /**
71 | * @param {Input} input
72 | * @param {RawSourceMap} [sourceMap]
73 | * @param {CustomOptions} [minimizerOptions]
74 | * @return {Promise}
75 | */
76 | async function cssnanoMinify(
77 | input,
78 | sourceMap,
79 | minimizerOptions = { preset: "default" },
80 | ) {
81 | /**
82 | * @template T
83 | * @param {string} module
84 | * @returns {Promise}
85 | */
86 | const load = async (module) => {
87 | let exports;
88 |
89 | try {
90 | // eslint-disable-next-line import/no-dynamic-require, global-require
91 | exports = require(module);
92 |
93 | return exports;
94 | } catch (requireError) {
95 | let importESM;
96 |
97 | try {
98 | // eslint-disable-next-line no-new-func
99 | importESM = new Function("id", "return import(id);");
100 | } catch (e) {
101 | importESM = null;
102 | }
103 |
104 | if (
105 | /** @type {Error & {code: string}} */
106 | (requireError).code === "ERR_REQUIRE_ESM" &&
107 | importESM
108 | ) {
109 | exports = await importESM(module);
110 |
111 | return exports.default;
112 | }
113 |
114 | throw requireError;
115 | }
116 | };
117 |
118 | const [[name, code]] = Object.entries(input);
119 | /** @type {ProcessOptions} */
120 | const postcssOptions = {
121 | from: name,
122 | ...minimizerOptions.processorOptions,
123 | };
124 |
125 | if (typeof postcssOptions.parser === "string") {
126 | try {
127 | postcssOptions.parser = await load(postcssOptions.parser);
128 | } catch (error) {
129 | throw new Error(
130 | `Loading PostCSS "${postcssOptions.parser}" parser failed: ${
131 | /** @type {Error} */ (error).message
132 | }\n\n(@${name})`,
133 | );
134 | }
135 | }
136 |
137 | if (typeof postcssOptions.stringifier === "string") {
138 | try {
139 | postcssOptions.stringifier = await load(postcssOptions.stringifier);
140 | } catch (error) {
141 | throw new Error(
142 | `Loading PostCSS "${postcssOptions.stringifier}" stringifier failed: ${
143 | /** @type {Error} */ (error).message
144 | }\n\n(@${name})`,
145 | );
146 | }
147 | }
148 |
149 | if (typeof postcssOptions.syntax === "string") {
150 | try {
151 | postcssOptions.syntax = await load(postcssOptions.syntax);
152 | } catch (error) {
153 | throw new Error(
154 | `Loading PostCSS "${postcssOptions.syntax}" syntax failed: ${
155 | /** @type {Error} */ (error).message
156 | }\n\n(@${name})`,
157 | );
158 | }
159 | }
160 |
161 | if (sourceMap) {
162 | postcssOptions.map = { annotation: false };
163 | }
164 |
165 | /** @type {Postcss} */
166 | // eslint-disable-next-line global-require
167 | const postcss = require("postcss").default;
168 | // @ts-ignore
169 | // eslint-disable-next-line global-require
170 | const cssnano = require("cssnano");
171 | // @ts-ignore
172 | // Types are broken
173 | const result = await postcss([cssnano(minimizerOptions)]).process(
174 | code,
175 | postcssOptions,
176 | );
177 |
178 | return {
179 | code: result.css,
180 | // @ts-ignore
181 | map: result.map
182 | ? result.map.toJSON()
183 | : // eslint-disable-next-line no-undefined
184 | undefined,
185 | warnings: result.warnings().map(String),
186 | };
187 | }
188 |
189 | cssnanoMinify.supportsWorkerThreads = () => true;
190 |
191 | /* istanbul ignore next */
192 | /**
193 | * @param {Input} input
194 | * @param {RawSourceMap} [sourceMap]
195 | * @param {CustomOptions} [minimizerOptions]
196 | * @return {Promise}
197 | */
198 | async function cssoMinify(input, sourceMap, minimizerOptions) {
199 | // eslint-disable-next-line global-require,import/no-extraneous-dependencies
200 | const csso = require("csso");
201 | const [[filename, code]] = Object.entries(input);
202 | const result = csso.minify(code, {
203 | filename,
204 | sourceMap: Boolean(sourceMap),
205 | ...minimizerOptions,
206 | });
207 |
208 | return {
209 | code: result.css,
210 | map: result.map
211 | ? /** @type {any & { toJSON(): RawSourceMap }} */
212 | (result.map).toJSON()
213 | : // eslint-disable-next-line no-undefined
214 | undefined,
215 | };
216 | }
217 |
218 | cssoMinify.supportsWorkerThreads = () => true;
219 |
220 | /* istanbul ignore next */
221 | /**
222 | * @param {Input} input
223 | * @param {RawSourceMap} [sourceMap]
224 | * @param {CustomOptions} [minimizerOptions]
225 | * @return {Promise}
226 | */
227 | async function cleanCssMinify(input, sourceMap, minimizerOptions) {
228 | // eslint-disable-next-line global-require,import/no-extraneous-dependencies
229 | const CleanCSS = require("clean-css");
230 | const [[name, code]] = Object.entries(input);
231 | const result = await new CleanCSS({
232 | sourceMap: Boolean(sourceMap),
233 | ...minimizerOptions,
234 | returnPromise: true,
235 | }).minify({ [name]: { styles: code } });
236 |
237 | const generatedSourceMap =
238 | result.sourceMap &&
239 | /** @type {any & { toJSON(): RawSourceMap }} */
240 | (result.sourceMap).toJSON();
241 |
242 | // workaround for source maps on windows
243 | if (generatedSourceMap) {
244 | // eslint-disable-next-line global-require
245 | const isWindowsPathSep = require("path").sep === "\\";
246 |
247 | generatedSourceMap.sources = generatedSourceMap.sources.map(
248 | /**
249 | * @param {string} item
250 | * @returns {string}
251 | */
252 | (item) => (isWindowsPathSep ? item.replace(/\\/g, "/") : item),
253 | );
254 | }
255 |
256 | return {
257 | code: result.styles,
258 | map: generatedSourceMap,
259 | warnings: result.warnings,
260 | };
261 | }
262 |
263 | cleanCssMinify.supportsWorkerThreads = () => true;
264 |
265 | /* istanbul ignore next */
266 | /**
267 | * @param {Input} input
268 | * @param {RawSourceMap} [sourceMap]
269 | * @param {CustomOptions} [minimizerOptions]
270 | * @return {Promise}
271 | */
272 | async function esbuildMinify(input, sourceMap, minimizerOptions) {
273 | /**
274 | * @param {import("esbuild").TransformOptions} [esbuildOptions={}]
275 | * @returns {import("esbuild").TransformOptions}
276 | */
277 | const buildEsbuildOptions = (esbuildOptions = {}) => {
278 | // Need deep copy objects to avoid https://github.com/terser/terser/issues/366
279 | return {
280 | loader: "css",
281 | minify: true,
282 | legalComments: "inline",
283 | ...esbuildOptions,
284 | sourcemap: false,
285 | };
286 | };
287 |
288 | // eslint-disable-next-line import/no-extraneous-dependencies, global-require
289 | const esbuild = require("esbuild");
290 |
291 | // Copy `esbuild` options
292 | const esbuildOptions = buildEsbuildOptions(minimizerOptions);
293 |
294 | // Let `esbuild` generate a SourceMap
295 | if (sourceMap) {
296 | esbuildOptions.sourcemap = true;
297 | esbuildOptions.sourcesContent = false;
298 | }
299 |
300 | const [[filename, code]] = Object.entries(input);
301 |
302 | esbuildOptions.sourcefile = filename;
303 |
304 | const result = await esbuild.transform(code, esbuildOptions);
305 |
306 | return {
307 | code: result.code,
308 | // eslint-disable-next-line no-undefined
309 | map: result.map ? JSON.parse(result.map) : undefined,
310 | warnings:
311 | result.warnings.length > 0
312 | ? result.warnings.map((item) => {
313 | return {
314 | source: item.location && item.location.file,
315 | line:
316 | item.location && item.location.line
317 | ? item.location.line
318 | : // eslint-disable-next-line no-undefined
319 | undefined,
320 | column:
321 | item.location && item.location.column
322 | ? item.location.column
323 | : // eslint-disable-next-line no-undefined
324 | undefined,
325 | plugin: item.pluginName,
326 | message: `${item.text}${
327 | item.detail ? `\nDetails:\n${item.detail}` : ""
328 | }${
329 | item.notes.length > 0
330 | ? `\n\nNotes:\n${item.notes
331 | .map(
332 | (note) =>
333 | `${
334 | note.location
335 | ? `[${note.location.file}:${note.location.line}:${note.location.column}] `
336 | : ""
337 | }${note.text}${
338 | note.location
339 | ? `\nSuggestion: ${note.location.suggestion}`
340 | : ""
341 | }${
342 | note.location
343 | ? `\nLine text:\n${note.location.lineText}\n`
344 | : ""
345 | }`,
346 | )
347 | .join("\n")}`
348 | : ""
349 | }`,
350 | };
351 | })
352 | : [],
353 | };
354 | }
355 |
356 | esbuildMinify.supportsWorkerThreads = () => false;
357 |
358 | // TODO remove in the next major release
359 | /* istanbul ignore next */
360 | /**
361 | * @param {Input} input
362 | * @param {RawSourceMap} [sourceMap]
363 | * @param {CustomOptions} [minimizerOptions]
364 | * @return {Promise}
365 | */
366 | async function parcelCssMinify(input, sourceMap, minimizerOptions) {
367 | const [[filename, code]] = Object.entries(input);
368 | /**
369 | * @param {Partial>} [parcelCssOptions={}]
370 | * @returns {import("@parcel/css").TransformOptions}
371 | */
372 | const buildParcelCssOptions = (parcelCssOptions = {}) => {
373 | // Need deep copy objects to avoid https://github.com/terser/terser/issues/366
374 | return {
375 | minify: true,
376 | ...parcelCssOptions,
377 | sourceMap: false,
378 | filename,
379 | code: Buffer.from(code),
380 | };
381 | };
382 |
383 | // eslint-disable-next-line import/no-extraneous-dependencies, global-require
384 | const parcelCss = require("@parcel/css");
385 |
386 | // Copy `parcel-css` options
387 | const parcelCssOptions = buildParcelCssOptions(minimizerOptions);
388 |
389 | // Let `esbuild` generate a SourceMap
390 | if (sourceMap) {
391 | parcelCssOptions.sourceMap = true;
392 | }
393 |
394 | const result = await parcelCss.transform(parcelCssOptions);
395 |
396 | return {
397 | code: result.code.toString(),
398 | // eslint-disable-next-line no-undefined
399 | map: result.map ? JSON.parse(result.map.toString()) : undefined,
400 | };
401 | }
402 |
403 | parcelCssMinify.supportsWorkerThreads = () => false;
404 |
405 | /* istanbul ignore next */
406 | /**
407 | * @param {Input} input
408 | * @param {RawSourceMap} [sourceMap]
409 | * @param {CustomOptions} [minimizerOptions]
410 | * @return {Promise}
411 | */
412 | async function lightningCssMinify(input, sourceMap, minimizerOptions) {
413 | const [[filename, code]] = Object.entries(input);
414 | /**
415 | * @param {Partial>} [lightningCssOptions={}]
416 | * @returns {import("lightningcss").TransformOptions}
417 | */
418 | const buildLightningCssOptions = (lightningCssOptions = {}) => {
419 | // Need deep copy objects to avoid https://github.com/terser/terser/issues/366
420 | return {
421 | minify: true,
422 | ...lightningCssOptions,
423 | sourceMap: false,
424 | filename,
425 | code: Buffer.from(code),
426 | };
427 | };
428 |
429 | // eslint-disable-next-line import/no-extraneous-dependencies, global-require
430 | const lightningCss = require("lightningcss");
431 |
432 | // Copy `lightningCss` options
433 | const lightningCssOptions = buildLightningCssOptions(minimizerOptions);
434 |
435 | // Let `esbuild` generate a SourceMap
436 | if (sourceMap) {
437 | lightningCssOptions.sourceMap = true;
438 | }
439 |
440 | const result = await lightningCss.transform(lightningCssOptions);
441 |
442 | return {
443 | code: result.code.toString(),
444 | // eslint-disable-next-line no-undefined
445 | map: result.map ? JSON.parse(result.map.toString()) : undefined,
446 | };
447 | }
448 |
449 | lightningCssMinify.supportsWorkerThreads = () => false;
450 |
451 | /* istanbul ignore next */
452 | /**
453 | * @param {Input} input
454 | * @param {RawSourceMap} [sourceMap]
455 | * @param {CustomOptions} [minimizerOptions]
456 | * @return {Promise}
457 | */
458 | async function swcMinify(input, sourceMap, minimizerOptions) {
459 | const [[filename, code]] = Object.entries(input);
460 | /**
461 | * @param {Partial} [swcOptions={}]
462 | * @returns {import("@swc/css").MinifyOptions}
463 | */
464 | const buildSwcOptions = (swcOptions = {}) => {
465 | // Need deep copy objects to avoid https://github.com/terser/terser/issues/366
466 | return {
467 | ...swcOptions,
468 | filename,
469 | };
470 | };
471 |
472 | // eslint-disable-next-line import/no-extraneous-dependencies, global-require
473 | const swc = require("@swc/css");
474 |
475 | // Copy `swc` options
476 | const swcOptions = buildSwcOptions(minimizerOptions);
477 |
478 | // Let `swc` generate a SourceMap
479 | if (sourceMap) {
480 | swcOptions.sourceMap = true;
481 | }
482 |
483 | const result = await swc.minify(Buffer.from(code), swcOptions);
484 |
485 | return {
486 | code: result.code.toString(),
487 | // eslint-disable-next-line no-undefined
488 | map: result.map ? JSON.parse(result.map.toString()) : undefined,
489 | errors: result.errors
490 | ? result.errors.map((diagnostic) => {
491 | const error = new Error(diagnostic.message);
492 |
493 | // @ts-ignore
494 | error.span = diagnostic.span;
495 | // @ts-ignore
496 | error.level = diagnostic.level;
497 |
498 | return error;
499 | })
500 | : // eslint-disable-next-line no-undefined
501 | undefined,
502 | };
503 | }
504 |
505 | swcMinify.supportsWorkerThreads = () => false;
506 |
507 | /**
508 | * @template T
509 | * @param fn {(function(): any) | undefined}
510 | * @returns {function(): T}
511 | */
512 | function memoize(fn) {
513 | let cache = false;
514 | /** @type {T} */
515 | let result;
516 |
517 | return () => {
518 | if (cache) {
519 | return result;
520 | }
521 | result = /** @type {function(): any} */ (fn)();
522 | cache = true;
523 | // Allow to clean up memory for fn
524 | // and all dependent resources
525 | // eslint-disable-next-line no-undefined, no-param-reassign
526 | fn = undefined;
527 |
528 | return result;
529 | };
530 | }
531 |
532 | module.exports = {
533 | throttleAll,
534 | memoize,
535 | cssnanoMinify,
536 | cssoMinify,
537 | cleanCssMinify,
538 | esbuildMinify,
539 | parcelCssMinify,
540 | lightningCssMinify,
541 | swcMinify,
542 | };
543 |
--------------------------------------------------------------------------------
/test/__snapshots__/CssMinimizerPlugin.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`CssMinimizerPlugin buildError method 1`] = `
4 | [Error: test.css from Css Minimizer plugin
5 | Message]
6 | `;
7 |
8 | exports[`CssMinimizerPlugin buildError method 2`] = `
9 | [Error: test.css from Css Minimizer plugin
10 | Message [test.css:1,1]]
11 | `;
12 |
13 | exports[`CssMinimizerPlugin buildError method 3`] = `
14 | [Error: test.css from Css Minimizer plugin
15 | Message [http://example.com/www/js/one.css:1,1][test.css:1,1]]
16 | `;
17 |
18 | exports[`CssMinimizerPlugin buildError method 4`] = `
19 | [Error: test.css from Css Minimizer plugin
20 | Stack]
21 | `;
22 |
23 | exports[`CssMinimizerPlugin buildWarning method 1`] = `
24 | [Warning: undefined from Css Minimizer plugin
25 | Warning test.css:1:1]
26 | `;
27 |
28 | exports[`CssMinimizerPlugin buildWarning method 2`] = `
29 | [Warning: test.css from Css Minimizer plugin
30 | Warning test.css:1:1]
31 | `;
32 |
33 | exports[`CssMinimizerPlugin buildWarning method 3`] = `
34 | [Warning: test.css from Css Minimizer plugin
35 | Warning test.css:1:1]
36 | `;
37 |
38 | exports[`CssMinimizerPlugin buildWarning method 4`] = `
39 | [Warning: test.css from Css Minimizer plugin
40 | Warning http://example.com/www/js/one.css:1:1]
41 | `;
42 |
43 | exports[`CssMinimizerPlugin buildWarning method 5`] = `
44 | [Warning: test.css from Css Minimizer plugin
45 | Warning http://example.com/www/js/one.css:1:1]
46 | `;
47 |
48 | exports[`CssMinimizerPlugin buildWarning method 6`] = `undefined`;
49 |
50 | exports[`CssMinimizerPlugin buildWarning method 7`] = `
51 | [Warning: test.css from Css Minimizer plugin
52 | warning http://example.com/www/js/one.css:1:1]
53 | `;
54 |
55 | exports[`CssMinimizerPlugin should build error: error 1`] = `
56 | [
57 | "Error: error.css from Css Minimizer plugin
58 | /error.css:1:1: Unknown word [error.css:1,1]",
59 | ]
60 | `;
61 |
62 | exports[`CssMinimizerPlugin should build error: warning 1`] = `[]`;
63 |
64 | exports[`CssMinimizerPlugin should build warning: error 1`] = `[]`;
65 |
66 | exports[`CssMinimizerPlugin should build warning: warning 1`] = `
67 | [
68 | "Warning: foo.css from Css Minimizer plugin
69 | [warning-plugin] Warning",
70 | ]
71 | `;
72 |
73 | exports[`CssMinimizerPlugin should respect the hash options #1: assets 1`] = `
74 | {
75 | "entry.css": "a{text-align:center}",
76 | }
77 | `;
78 |
79 | exports[`CssMinimizerPlugin should respect the hash options #1: errors 1`] = `[]`;
80 |
81 | exports[`CssMinimizerPlugin should respect the hash options #1: warnings 1`] = `[]`;
82 |
83 | exports[`CssMinimizerPlugin should run plugin against assets added later by plugins: assets 1`] = `
84 | {
85 | "newFile.css": ".a{color:coral;display:block}",
86 | }
87 | `;
88 |
89 | exports[`CssMinimizerPlugin should run plugin against assets added later by plugins: errors 1`] = `[]`;
90 |
91 | exports[`CssMinimizerPlugin should run plugin against assets added later by plugins: warnings 1`] = `[]`;
92 |
93 | exports[`CssMinimizerPlugin should throw error from postcss: error 1`] = `
94 | [
95 | "Error: foo.css from Css Minimizer plugin
96 | error-plugin: /foo.css:2:3: Postcss error [webpack://./test/foo.css:2,2][foo.css:2,3]",
97 | ]
98 | `;
99 |
100 | exports[`CssMinimizerPlugin should throw error from postcss: warning 1`] = `[]`;
101 |
102 | exports[`CssMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": assets 1`] = `
103 | {
104 | "foo.css": "body{color:red}a{color:blue}",
105 | "style-2.css": "a{color:coral}",
106 | "style.css": "a{color:red}",
107 | }
108 | `;
109 |
110 | exports[`CssMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": assets 2`] = `
111 | {
112 | "foo.css": "body{color:red}a{color:blue}",
113 | "style-2.css": "a{color:coral}",
114 | "style.css": "a{color:red}",
115 | }
116 | `;
117 |
118 | exports[`CssMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": errors 1`] = `[]`;
119 |
120 | exports[`CssMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": errors 2`] = `[]`;
121 |
122 | exports[`CssMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": warnings 1`] = `[]`;
123 |
124 | exports[`CssMinimizerPlugin should work and do not use memory cache when the "cache" option is "false": warnings 2`] = `[]`;
125 |
126 | exports[`CssMinimizerPlugin should work and generate real content hash: assets 1`] = `
127 | {
128 | "entry.ee68cb428fa1feaa2c48.072159461f23c2c047e9.0e6907f00e0eaf46a2f9.css": "body{color:red}a{color:blue}",
129 | }
130 | `;
131 |
132 | exports[`CssMinimizerPlugin should work and generate real content hash: errors 1`] = `[]`;
133 |
134 | exports[`CssMinimizerPlugin should work and generate real content hash: warnings 1`] = `[]`;
135 |
136 | exports[`CssMinimizerPlugin should work and show minimized assets in stats: assets 1`] = `
137 | {
138 | "foo.css": "body{color:red}a{color:blue}",
139 | }
140 | `;
141 |
142 | exports[`CssMinimizerPlugin should work and show minimized assets in stats: errors 1`] = `[]`;
143 |
144 | exports[`CssMinimizerPlugin should work and show minimized assets in stats: warnings 1`] = `[]`;
145 |
146 | exports[`CssMinimizerPlugin should work and use memory cache out of box: assets 1`] = `
147 | {
148 | "foo.css": "body{color:red}a{color:blue}",
149 | "style-2.css": "a{color:coral}",
150 | "style.css": "a{color:red}",
151 | }
152 | `;
153 |
154 | exports[`CssMinimizerPlugin should work and use memory cache out of box: assets 2`] = `
155 | {
156 | "foo.css": "body{color:red}a{color:blue}",
157 | "style-2.css": "a{color:coral}",
158 | "style.css": "a{color:red}",
159 | }
160 | `;
161 |
162 | exports[`CssMinimizerPlugin should work and use memory cache out of box: errors 1`] = `[]`;
163 |
164 | exports[`CssMinimizerPlugin should work and use memory cache out of box: errors 2`] = `[]`;
165 |
166 | exports[`CssMinimizerPlugin should work and use memory cache out of box: warnings 1`] = `[]`;
167 |
168 | exports[`CssMinimizerPlugin should work and use memory cache out of box: warnings 2`] = `[]`;
169 |
170 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: assets 1`] = `
171 | {
172 | "foo.css": "body{color:red}a{color:blue}",
173 | "style-2.css": "a{color:coral}",
174 | "style.css": "a{color:red}",
175 | }
176 | `;
177 |
178 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: assets 2`] = `
179 | {
180 | "foo.css": "a,body{color:red}a{color:blue}",
181 | "style-2.css": "a{color:coral}",
182 | "style.css": "a{color:red}",
183 | }
184 | `;
185 |
186 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: errors 1`] = `[]`;
187 |
188 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: errors 2`] = `[]`;
189 |
190 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 1`] = `[]`;
191 |
192 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 2`] = `[]`;
193 |
194 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true": assets 1`] = `
195 | {
196 | "foo.css": "body{color:red}a{color:blue}",
197 | "style-2.css": "a{color:coral}",
198 | "style.css": "a{color:red}",
199 | }
200 | `;
201 |
202 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true": assets 2`] = `
203 | {
204 | "foo.css": "body{color:red}a{color:blue}",
205 | "style-2.css": "a{color:coral}",
206 | "style.css": "a{color:red}",
207 | }
208 | `;
209 |
210 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true": errors 1`] = `[]`;
211 |
212 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true": errors 2`] = `[]`;
213 |
214 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true": warnings 1`] = `[]`;
215 |
216 | exports[`CssMinimizerPlugin should work and use memory cache when the "cache" option is "true": warnings 2`] = `[]`;
217 |
218 | exports[`CssMinimizerPlugin should work with assets using querystring: entry.css.map?v=test 1`] = `"{"version":3,"file":"entry.css?v=test","mappings":"AAAA,KACE,SACF,CACA,EACE,UACF","sources":["webpack:///entry.css%3Fv=test"],"sourcesContent":["body {\\n color: red;\\n}\\na {\\n color: blue;\\n}\\n"],"names":[],"sourceRoot":""}"`;
219 |
220 | exports[`CssMinimizerPlugin should work with assets using querystring: entry.css?v=test 1`] = `
221 | "body{color:red}a{color:blue}
222 | /*# sourceMappingURL=entry.css.map?v=test*/"
223 | `;
224 |
225 | exports[`CssMinimizerPlugin should work with child compilation: assets 1`] = `
226 | {
227 | "entry.css": ".entry{text-align:center}",
228 | }
229 | `;
230 |
231 | exports[`CssMinimizerPlugin should work with child compilation: errors 1`] = `[]`;
232 |
233 | exports[`CssMinimizerPlugin should work with child compilation: warnings 1`] = `[]`;
234 |
235 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true" and the asset has been changed: assets 1`] = `
236 | {
237 | "foo.css": "body{color:red}a{color:blue}
238 | /*# sourceMappingURL=foo.css.map*/",
239 | "foo.css.map": "{"version":3,"file":"foo.css","mappings":"AAAA,KACE,SACF,CACA,EACE,UACF","sources":["webpack:///./foo.css"],"sourcesContent":["body {\\n color: red;\\n}\\na {\\n color: blue;\\n}"],"names":[],"sourceRoot":""}",
240 | "style-2.css": "a{color:coral}",
241 | "style.css": "a{color:red}",
242 | }
243 | `;
244 |
245 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true" and the asset has been changed: assets 2`] = `
246 | {
247 | "foo.css": "a,body{color:red}a{color:blue}
248 | /*# sourceMappingURL=foo.css.map*/",
249 | "foo.css.map": "{"version":3,"file":"foo.css","mappings":"AAAA,OACE,SACF,CACA,EACE,UACF","sources":["webpack:///./foo.css"],"sourcesContent":["body {\\n color: red;\\n}\\na {\\n color: blue;\\n}"],"names":[],"sourceRoot":""}",
250 | "style-2.css": "a{color:coral}",
251 | "style.css": "a{color:red}",
252 | }
253 | `;
254 |
255 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true" and the asset has been changed: errors 1`] = `[]`;
256 |
257 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true" and the asset has been changed: errors 2`] = `[]`;
258 |
259 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 1`] = `[]`;
260 |
261 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 2`] = `[]`;
262 |
263 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true": assets 1`] = `
264 | {
265 | "foo.css": "body{color:red}a{color:blue}
266 | /*# sourceMappingURL=foo.css.map*/",
267 | "foo.css.map": "{"version":3,"file":"foo.css","mappings":"AAAA,KACE,SACF,CACA,EACE,UACF","sources":["webpack:///./foo.css"],"sourcesContent":["body {\\n color: red;\\n}\\na {\\n color: blue;\\n}"],"names":[],"sourceRoot":""}",
268 | "style-2.css": "a{color:coral}",
269 | "style.css": "a{color:red}",
270 | }
271 | `;
272 |
273 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true": assets 2`] = `
274 | {
275 | "foo.css": "body{color:red}a{color:blue}
276 | /*# sourceMappingURL=foo.css.map*/",
277 | "foo.css.map": "{"version":3,"file":"foo.css","mappings":"AAAA,KACE,SACF,CACA,EACE,UACF","sources":["webpack:///./foo.css"],"sourcesContent":["body {\\n color: red;\\n}\\na {\\n color: blue;\\n}"],"names":[],"sourceRoot":""}",
278 | "style-2.css": "a{color:coral}",
279 | "style.css": "a{color:red}",
280 | }
281 | `;
282 |
283 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true": errors 1`] = `[]`;
284 |
285 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true": errors 2`] = `[]`;
286 |
287 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true": warnings 1`] = `[]`;
288 |
289 | exports[`CssMinimizerPlugin should work with source map and use memory cache when the "cache" option is "true": warnings 2`] = `[]`;
290 |
291 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: assets 1`] = `
292 | {
293 | "foo.css": "body {
294 | color: red;
295 | }
296 | a {
297 | color: blue;
298 | }
299 | ",
300 | "style-2.css": "a { color: coral; }",
301 | "style.css": "a { color: red; }",
302 | }
303 | `;
304 |
305 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: assets 2`] = `
306 | {
307 | "foo.css": "a { color: red; }body {
308 | color: red;
309 | }
310 | a {
311 | color: blue;
312 | }
313 | ",
314 | "style-2.css": "a { color: coral; }",
315 | "style.css": "a { color: red; }",
316 | }
317 | `;
318 |
319 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: errors 1`] = `
320 | [
321 | "Warning: foo.css from Css Minimizer plugin
322 | [warning-plugin] Warning from foo.css",
323 | "Warning: style-2.css from Css Minimizer plugin
324 | [warning-plugin] Warning from style-2.css",
325 | "Warning: style.css from Css Minimizer plugin
326 | [warning-plugin] Warning from style.css",
327 | ]
328 | `;
329 |
330 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: errors 2`] = `[]`;
331 |
332 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 1`] = `[]`;
333 |
334 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true" and the asset has been changed: warnings 2`] = `
335 | [
336 | "Warning: foo.css from Css Minimizer plugin
337 | [warning-plugin] Warning from foo.css",
338 | "Warning: style-2.css from Css Minimizer plugin
339 | [warning-plugin] Warning from style-2.css",
340 | "Warning: style.css from Css Minimizer plugin
341 | [warning-plugin] Warning from style.css",
342 | ]
343 | `;
344 |
345 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": assets 1`] = `
346 | {
347 | "foo.css": "body {
348 | color: red;
349 | }
350 | a {
351 | color: blue;
352 | }
353 | ",
354 | "style-2.css": "a { color: coral; }",
355 | "style.css": "a { color: red; }",
356 | }
357 | `;
358 |
359 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": assets 2`] = `
360 | {
361 | "foo.css": "body {
362 | color: red;
363 | }
364 | a {
365 | color: blue;
366 | }
367 | ",
368 | "style-2.css": "a { color: coral; }",
369 | "style.css": "a { color: red; }",
370 | }
371 | `;
372 |
373 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": errors 1`] = `
374 | [
375 | "Warning: foo.css from Css Minimizer plugin
376 | [warning-plugin] Warning from foo.css",
377 | "Warning: style-2.css from Css Minimizer plugin
378 | [warning-plugin] Warning from style-2.css",
379 | "Warning: style.css from Css Minimizer plugin
380 | [warning-plugin] Warning from style.css",
381 | ]
382 | `;
383 |
384 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": errors 2`] = `[]`;
385 |
386 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": warnings 1`] = `[]`;
387 |
388 | exports[`CssMinimizerPlugin should work with warnings and use memory cache when the "cache" option is "true": warnings 2`] = `
389 | [
390 | "Warning: foo.css from Css Minimizer plugin
391 | [warning-plugin] Warning from foo.css",
392 | "Warning: style-2.css from Css Minimizer plugin
393 | [warning-plugin] Warning from style-2.css",
394 | "Warning: style.css from Css Minimizer plugin
395 | [warning-plugin] Warning from style.css",
396 | ]
397 | `;
398 |
399 | exports[`CssMinimizerPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: assets 1`] = `
400 | {
401 | "one.css": ".minify {};",
402 | "two.css": ".minify {};",
403 | }
404 | `;
405 |
406 | exports[`CssMinimizerPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: errors 1`] = `[]`;
407 |
408 | exports[`CssMinimizerPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: process stderr output 1`] = `
409 | "stderr
410 | stderr
411 | "
412 | `;
413 |
414 | exports[`CssMinimizerPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: process stdout output 1`] = `
415 | "stdout
416 | stdout
417 | "
418 | `;
419 |
420 | exports[`CssMinimizerPlugin should write stdout and stderr of workers to stdout and stderr of main process in parallel mode: warnings 1`] = `[]`;
421 |
--------------------------------------------------------------------------------
/test/__snapshots__/cache-option.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`"cache" option should work with the "false" value for the "cache" option: assets 1`] = `
4 | {
5 | "five.css": "body{color:red;font-size:20px}a{color:blue}",
6 | "four.css": "h1{color:green}h2{color:#ff0}",
7 | "one.css": "a{text-align:center}",
8 | "three.css": "body{color:red;font-size:20px}a{color:blue}",
9 | "two.css": "a{text-align:center}",
10 | }
11 | `;
12 |
13 | exports[`"cache" option should work with the "false" value for the "cache" option: assets 2`] = `
14 | {
15 | "five.css": "body{color:red;font-size:20px}a{color:blue}",
16 | "four.css": "h1{color:green}h2{color:#ff0}",
17 | "one.css": "a{text-align:center}",
18 | "three.css": "body{color:red;font-size:20px}a{color:blue}",
19 | "two.css": "a{text-align:center}",
20 | }
21 | `;
22 |
23 | exports[`"cache" option should work with the "false" value for the "cache" option: errors 1`] = `[]`;
24 |
25 | exports[`"cache" option should work with the "false" value for the "cache" option: errors 2`] = `[]`;
26 |
27 | exports[`"cache" option should work with the "false" value for the "cache" option: warnings 1`] = `[]`;
28 |
29 | exports[`"cache" option should work with the "false" value for the "cache" option: warnings 2`] = `[]`;
30 |
31 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: assets 1`] = `
32 | {
33 | "five.css": "body {
34 | color: red;
35 | }
36 | body {
37 | color: red;
38 | font-size: 20px;
39 | }
40 | a {
41 | color: blue;
42 | }
43 |
44 | ",
45 | "four.css": "h1 {
46 | color: green;
47 | }
48 | h2 {
49 | color: yellow;
50 | }
51 | h3 {
52 | }
53 |
54 | ",
55 | "one.css": "a {
56 | text-align: center;
57 | }
58 |
59 | ",
60 | "three.css": "body {
61 | color: red;
62 | }
63 | body {
64 | color: red;
65 | font-size: 20px;
66 | }
67 | a {
68 | color: blue;
69 | }
70 |
71 | ",
72 | "two.css": "a {
73 | text-align: center;
74 | }
75 |
76 | ",
77 | }
78 | `;
79 |
80 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: assets 2`] = `
81 | {
82 | "five.css": "body {
83 | color: red;
84 | }
85 | body {
86 | color: red;
87 | font-size: 20px;
88 | }
89 | a {
90 | color: blue;
91 | }
92 |
93 | ",
94 | "four.css": "h1 {
95 | color: green;
96 | }
97 | h2 {
98 | color: yellow;
99 | }
100 | h3 {
101 | }
102 |
103 | ",
104 | "one.css": "a {
105 | text-align: center;
106 | }
107 |
108 | ",
109 | "three.css": "body {
110 | color: red;
111 | }
112 | body {
113 | color: red;
114 | font-size: 20px;
115 | }
116 | a {
117 | color: blue;
118 | }
119 |
120 | ",
121 | "two.css": "a {
122 | text-align: center;
123 | }
124 |
125 | ",
126 | }
127 | `;
128 |
129 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: errors 1`] = `[]`;
130 |
131 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: errors 2`] = `[]`;
132 |
133 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: warnings 1`] = `
134 | [
135 | "Warning: five.css from Css Minimizer plugin
136 | [warning-plugin] Warning from five.css",
137 | "Warning: four.css from Css Minimizer plugin
138 | [warning-plugin] Warning from four.css",
139 | "Warning: one.css from Css Minimizer plugin
140 | [warning-plugin] Warning from one.css",
141 | "Warning: three.css from Css Minimizer plugin
142 | [warning-plugin] Warning from three.css",
143 | "Warning: two.css from Css Minimizer plugin
144 | [warning-plugin] Warning from two.css",
145 | ]
146 | `;
147 |
148 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and output warnings: warnings 2`] = `
149 | [
150 | "Warning: five.css from Css Minimizer plugin
151 | [warning-plugin] Warning from five.css",
152 | "Warning: four.css from Css Minimizer plugin
153 | [warning-plugin] Warning from four.css",
154 | "Warning: one.css from Css Minimizer plugin
155 | [warning-plugin] Warning from one.css",
156 | "Warning: three.css from Css Minimizer plugin
157 | [warning-plugin] Warning from three.css",
158 | "Warning: two.css from Css Minimizer plugin
159 | [warning-plugin] Warning from two.css",
160 | ]
161 | `;
162 |
163 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and source maps: assets 1`] = `
164 | {
165 | "five.css": "body{color:red;font-size:20px}a{color:blue}
166 | /*# sourceMappingURL=five.css.map*/",
167 | "five.css.map": "{"version":3,"file":"five.css","mappings":"AAGA,KACE,SAAU,CACV,cACF,CACA,EACE,UACF","sources":["webpack:///./test/bar1.css"],"sourcesContent":["body {\\n color: red;\\n}\\nbody {\\n color: red;\\n font-size: 20px;\\n}\\na {\\n color: blue;\\n}\\n"],"names":[],"sourceRoot":""}",
168 | "four.css": "h1{color:green}h2{color:#ff0}
169 | /*# sourceMappingURL=four.css.map*/",
170 | "four.css.map": "{"version":3,"file":"four.css","mappings":"AAAA,GACE,WACF,CACA,GACE,UACF","sources":["webpack:///./test/bar2.css"],"sourcesContent":["h1 {\\n color: green;\\n}\\nh2 {\\n color: yellow;\\n}\\nh3 {\\n}\\n"],"names":[],"sourceRoot":""}",
171 | "one.css": "a{text-align:center}
172 | /*# sourceMappingURL=one.css.map*/",
173 | "one.css.map": "{"version":3,"file":"one.css","mappings":"AAAA,EACE,iBACF","sources":["webpack:///./test/foo.css"],"sourcesContent":["a {\\n text-align: center;\\n}\\n"],"names":[],"sourceRoot":""}",
174 | "three.css": "body{color:red;font-size:20px}a{color:blue}
175 | /*# sourceMappingURL=three.css.map*/",
176 | "three.css.map": "{"version":3,"file":"three.css","mappings":"AAGA,KACE,SAAU,CACV,cACF,CACA,EACE,UACF","sources":["webpack:///./test/bar1.css"],"sourcesContent":["body {\\n color: red;\\n}\\nbody {\\n color: red;\\n font-size: 20px;\\n}\\na {\\n color: blue;\\n}\\n"],"names":[],"sourceRoot":""}",
177 | "two.css": "a{text-align:center}
178 | /*# sourceMappingURL=two.css.map*/",
179 | "two.css.map": "{"version":3,"file":"two.css","mappings":"AAAA,EACE,iBACF","sources":["webpack:///./test/foo.css"],"sourcesContent":["a {\\n text-align: center;\\n}\\n"],"names":[],"sourceRoot":""}",
180 | }
181 | `;
182 |
183 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and source maps: assets 2`] = `
184 | {
185 | "five.css": "body{color:red;font-size:20px}a{color:blue}
186 | /*# sourceMappingURL=five.css.map*/",
187 | "five.css.map": "{"version":3,"file":"five.css","mappings":"AAGA,KACE,SAAU,CACV,cACF,CACA,EACE,UACF","sources":["webpack:///./test/bar1.css"],"sourcesContent":["body {\\n color: red;\\n}\\nbody {\\n color: red;\\n font-size: 20px;\\n}\\na {\\n color: blue;\\n}\\n"],"names":[],"sourceRoot":""}",
188 | "four.css": "h1{color:green}h2{color:#ff0}
189 | /*# sourceMappingURL=four.css.map*/",
190 | "four.css.map": "{"version":3,"file":"four.css","mappings":"AAAA,GACE,WACF,CACA,GACE,UACF","sources":["webpack:///./test/bar2.css"],"sourcesContent":["h1 {\\n color: green;\\n}\\nh2 {\\n color: yellow;\\n}\\nh3 {\\n}\\n"],"names":[],"sourceRoot":""}",
191 | "one.css": "a{text-align:center}
192 | /*# sourceMappingURL=one.css.map*/",
193 | "one.css.map": "{"version":3,"file":"one.css","mappings":"AAAA,EACE,iBACF","sources":["webpack:///./test/foo.css"],"sourcesContent":["a {\\n text-align: center;\\n}\\n"],"names":[],"sourceRoot":""}",
194 | "three.css": "body{color:red;font-size:20px}a{color:blue}
195 | /*# sourceMappingURL=three.css.map*/",
196 | "three.css.map": "{"version":3,"file":"three.css","mappings":"AAGA,KACE,SAAU,CACV,cACF,CACA,EACE,UACF","sources":["webpack:///./test/bar1.css"],"sourcesContent":["body {\\n color: red;\\n}\\nbody {\\n color: red;\\n font-size: 20px;\\n}\\na {\\n color: blue;\\n}\\n"],"names":[],"sourceRoot":""}",
197 | "two.css": "a{text-align:center}
198 | /*# sourceMappingURL=two.css.map*/",
199 | "two.css.map": "{"version":3,"file":"two.css","mappings":"AAAA,EACE,iBACF","sources":["webpack:///./test/foo.css"],"sourcesContent":["a {\\n text-align: center;\\n}\\n"],"names":[],"sourceRoot":""}",
200 | }
201 | `;
202 |
203 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and source maps: errors 1`] = `[]`;
204 |
205 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and source maps: errors 2`] = `[]`;
206 |
207 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and source maps: warnings 1`] = `[]`;
208 |
209 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option and source maps: warnings 2`] = `[]`;
210 |
211 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option: assets 1`] = `
212 | {
213 | "five.css": "body{color:red;font-size:20px}a{color:blue}",
214 | "four.css": "h1{color:green}h2{color:#ff0}",
215 | "one.css": "a{text-align:center}",
216 | "three.css": "body{color:red;font-size:20px}a{color:blue}",
217 | "two.css": "a{text-align:center}",
218 | }
219 | `;
220 |
221 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option: assets 2`] = `
222 | {
223 | "five.css": "body{color:red;font-size:20px}a{color:blue}",
224 | "four.css": "h1{color:green}h2{color:#ff0}",
225 | "one.css": "a{text-align:center}",
226 | "three.css": "body{color:red;font-size:20px}a{color:blue}",
227 | "two.css": "a{text-align:center}",
228 | }
229 | `;
230 |
231 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option: errors 1`] = `[]`;
232 |
233 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option: errors 2`] = `[]`;
234 |
235 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option: warnings 1`] = `[]`;
236 |
237 | exports[`"cache" option should work with the "filesystem" value for the "cache.type" option: warnings 2`] = `[]`;
238 |
239 | exports[`"cache" option should work with the "memory" value for the "cache.type" option: assets 1`] = `
240 | {
241 | "five.css": "body{color:red;font-size:20px}a{color:blue}",
242 | "four.css": "h1{color:green}h2{color:#ff0}",
243 | "one.css": "a{text-align:center}",
244 | "three.css": "body{color:red;font-size:20px}a{color:blue}",
245 | "two.css": "a{text-align:center}",
246 | }
247 | `;
248 |
249 | exports[`"cache" option should work with the "memory" value for the "cache.type" option: assets 2`] = `
250 | {
251 | "five.css": "body{color:red;font-size:20px}a{color:blue}",
252 | "four.css": "h1{color:green}h2{color:#ff0}",
253 | "one.css": "a{text-align:center}",
254 | "three.css": "body{color:red;font-size:20px}a{color:blue}",
255 | "two.css": "a{text-align:center}",
256 | }
257 | `;
258 |
259 | exports[`"cache" option should work with the "memory" value for the "cache.type" option: errors 1`] = `[]`;
260 |
261 | exports[`"cache" option should work with the "memory" value for the "cache.type" option: errors 2`] = `[]`;
262 |
263 | exports[`"cache" option should work with the "memory" value for the "cache.type" option: warnings 1`] = `[]`;
264 |
265 | exports[`"cache" option should work with the "memory" value for the "cache.type" option: warnings 2`] = `[]`;
266 |
--------------------------------------------------------------------------------
/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 excluded1: assets 1`] = `
4 | {
5 | "entry.css": "body{color:red}a{color:blue}",
6 | "excluded1.css": "a {
7 | text-align: center;
8 | }
9 |
10 | ",
11 | "excluded2.css": "body{color:red;font-size:20px}a{color:blue}",
12 | }
13 | `;
14 |
15 | exports[`exclude option should match snapshot for a single RegExp value excluded1: errors 1`] = `[]`;
16 |
17 | exports[`exclude option should match snapshot for a single RegExp value excluded1: warnings 1`] = `[]`;
18 |
19 | exports[`exclude option should match snapshot for a single String value excluded1: assets 1`] = `
20 | {
21 | "entry.css": "body{color:red}a{color:blue}",
22 | "excluded1.css": "a {
23 | text-align: center;
24 | }
25 |
26 | ",
27 | "excluded2.css": "body{color:red;font-size:20px}a{color:blue}",
28 | }
29 | `;
30 |
31 | exports[`exclude option should match snapshot for a single String value excluded1: errors 1`] = `[]`;
32 |
33 | exports[`exclude option should match snapshot for a single String value excluded1: warnings 1`] = `[]`;
34 |
35 | exports[`exclude option should match snapshot for multiple RegExp values excluded1 and excluded2: assets 1`] = `
36 | {
37 | "entry.css": "body{color:red}a{color:blue}",
38 | "excluded1.css": "a {
39 | text-align: center;
40 | }
41 |
42 | ",
43 | "excluded2.css": "body {
44 | color: red;
45 | }
46 | body {
47 | color: red;
48 | font-size: 20px;
49 | }
50 | a {
51 | color: blue;
52 | }
53 |
54 | ",
55 | }
56 | `;
57 |
58 | exports[`exclude option should match snapshot for multiple RegExp values excluded1 and excluded2: errors 1`] = `[]`;
59 |
60 | exports[`exclude option should match snapshot for multiple RegExp values excluded1 and excluded2: warnings 1`] = `[]`;
61 |
62 | exports[`exclude option should match snapshot for multiple String values excluded1 and excluded2: assets 1`] = `
63 | {
64 | "entry.css": "body{color:red}a{color:blue}",
65 | "excluded1.css": "a {
66 | text-align: center;
67 | }
68 |
69 | ",
70 | "excluded2.css": "body {
71 | color: red;
72 | }
73 | body {
74 | color: red;
75 | font-size: 20px;
76 | }
77 | a {
78 | color: blue;
79 | }
80 |
81 | ",
82 | }
83 | `;
84 |
85 | exports[`exclude option should match snapshot for multiple String values excluded1 and excluded2: errors 1`] = `[]`;
86 |
87 | exports[`exclude option should match snapshot for multiple String values excluded1 and excluded2: warnings 1`] = `[]`;
88 |
--------------------------------------------------------------------------------
/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 included1: assets 1`] = `
4 | {
5 | "entry.css": "body {
6 | color: red;
7 | }
8 | a {
9 | color: blue;
10 | }
11 | ",
12 | "included1.css": "a{text-align:center}",
13 | "included2.css": "body {
14 | color: red;
15 | }
16 | body {
17 | color: red;
18 | font-size: 20px;
19 | }
20 | a {
21 | color: blue;
22 | }
23 |
24 | ",
25 | }
26 | `;
27 |
28 | exports[`include option should match snapshot for a single RegExp value included1: errors 1`] = `[]`;
29 |
30 | exports[`include option should match snapshot for a single RegExp value included1: warnings 1`] = `[]`;
31 |
32 | exports[`include option should match snapshot for a single String value included1: assets 1`] = `
33 | {
34 | "entry.css": "body {
35 | color: red;
36 | }
37 | a {
38 | color: blue;
39 | }
40 | ",
41 | "included1.css": "a{text-align:center}",
42 | "included2.css": "body {
43 | color: red;
44 | }
45 | body {
46 | color: red;
47 | font-size: 20px;
48 | }
49 | a {
50 | color: blue;
51 | }
52 |
53 | ",
54 | }
55 | `;
56 |
57 | exports[`include option should match snapshot for a single String value included1: errors 1`] = `[]`;
58 |
59 | exports[`include option should match snapshot for a single String value included1: warnings 1`] = `[]`;
60 |
61 | exports[`include option should match snapshot for multiple RegExp values included1 and included2: assets 1`] = `
62 | {
63 | "entry.css": "body {
64 | color: red;
65 | }
66 | a {
67 | color: blue;
68 | }
69 | ",
70 | "included1.css": "a{text-align:center}",
71 | "included2.css": "body{color:red;font-size:20px}a{color:blue}",
72 | }
73 | `;
74 |
75 | exports[`include option should match snapshot for multiple RegExp values included1 and included2: errors 1`] = `[]`;
76 |
77 | exports[`include option should match snapshot for multiple RegExp values included1 and included2: warnings 1`] = `[]`;
78 |
79 | exports[`include option should match snapshot for multiple String values included1 and included2: assets 1`] = `
80 | {
81 | "entry.css": "body {
82 | color: red;
83 | }
84 | a {
85 | color: blue;
86 | }
87 | ",
88 | "included1.css": "a{text-align:center}",
89 | "included2.css": "body{color:red;font-size:20px}a{color:blue}",
90 | }
91 | `;
92 |
93 | exports[`include option should match snapshot for multiple String values included1 and included2: errors 1`] = `[]`;
94 |
95 | exports[`include option should match snapshot for multiple String values included1 and included2: warnings 1`] = `[]`;
96 |
--------------------------------------------------------------------------------
/test/__snapshots__/minimizerOptions-option.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`when applied with "minimizerOptions" option matches snapshot for "discardComments" option (disable): entry.css 1`] = `
4 | "body{
5 | /* this is a comment */
6 | /*! this is a comment with exclamation mark */color:red}"
7 | `;
8 |
9 | exports[`when applied with "minimizerOptions" option matches snapshot for "discardComments" option (enable [default]): entry.css 1`] = `
10 | "body{
11 | /*! this is a comment with exclamation mark */color:red}"
12 | `;
13 |
14 | exports[`when applied with "minimizerOptions" option matches snapshot for "discardComments" option (enable, with "removeAll" option): entry.css 1`] = `"body{color:red}"`;
15 |
16 | exports[`when applied with "minimizerOptions" option matches snapshot for "discardEmpty" option (disable): entry.css 1`] = `"@layer ui-components, foo-bar;body{color:red}a{}.foo{color:#000;& .class{color:#fff}}@layer ui-components{}"`;
17 |
18 | exports[`when applied with "minimizerOptions" option matches snapshot for "discardEmpty" option (enable [default]): entry.css 1`] = `"@layer ui-components, foo-bar;body{color:red}.foo{color:#000;& .class{color:#fff}}@layer ui-components{}"`;
19 |
20 | exports[`when applied with "minimizerOptions" option matches snapshot for "mergeRules" option (disable): entry.css 1`] = `"body{color:red}body{font-weight:700}"`;
21 |
22 | exports[`when applied with "minimizerOptions" option matches snapshot for "mergeRules" option (enable [default]): entry.css 1`] = `"body{color:red;font-weight:700}"`;
23 |
24 | exports[`when applied with "minimizerOptions" option matches snapshot for "parser" option with "Function" value: index.sss 1`] = `"a{color:#000}"`;
25 |
26 | exports[`when applied with "minimizerOptions" option matches snapshot for "parser" option with "String" value: index.sss 1`] = `"a{color:#000}"`;
27 |
28 | exports[`when applied with "minimizerOptions" option matches snapshot for "preset" option with require.resolve "String" value: default-preset 1`] = `"p{border-radius:var(--test);border-width:1px;border:0 solid var(--test)}"`;
29 |
30 | exports[`when applied with "minimizerOptions" option matches snapshot for "preset" option with require.resolve "String" value: preset-simple 1`] = `"p{border-radius:var(--test);border-width:1px;border:0 solid var(--test)}"`;
31 |
32 | exports[`when applied with "minimizerOptions" option matches snapshot for "stringifier" option with "Function" value: entry.css 1`] = `"body color:reda color:blue"`;
33 |
34 | exports[`when applied with "minimizerOptions" option matches snapshot for "stringifier" option with "String" value: entry.css 1`] = `"body color:reda color:blue"`;
35 |
36 | exports[`when applied with "minimizerOptions" option matches snapshot for "syntax" option with "Function" value: index.sss 1`] = `"a color:#000"`;
37 |
38 | exports[`when applied with "minimizerOptions" option matches snapshot for "syntax" option with "String" value: index.sss 1`] = `"a color:#000"`;
39 |
--------------------------------------------------------------------------------
/test/__snapshots__/parallel-option.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`parallel option should match snapshot for the "2" value: assets 1`] = `
4 | {
5 | "four.css": "body{color:red}a{color:blue}",
6 | "one.css": "body{color:red}a{color:blue}",
7 | "three.css": "body{color:red}a{color:blue}",
8 | "two.css": "body{color:red}a{color:blue}",
9 | }
10 | `;
11 |
12 | exports[`parallel option should match snapshot for the "2" value: errors 1`] = `[]`;
13 |
14 | exports[`parallel option should match snapshot for the "2" value: warnings 1`] = `[]`;
15 |
16 | exports[`parallel option should match snapshot for the "false" value: assets 1`] = `
17 | {
18 | "four.css": "body{color:red}a{color:blue}",
19 | "one.css": "body{color:red}a{color:blue}",
20 | "three.css": "body{color:red}a{color:blue}",
21 | "two.css": "body{color:red}a{color:blue}",
22 | }
23 | `;
24 |
25 | exports[`parallel option should match snapshot for the "false" value: errors 1`] = `[]`;
26 |
27 | exports[`parallel option should match snapshot for the "false" value: warnings 1`] = `[]`;
28 |
29 | exports[`parallel option should match snapshot for the "true" value and the number of files is less than the number of cores: assets 1`] = `
30 | {
31 | "entry-0.css": "body{color:red}a{color:blue}",
32 | "entry-1.css": "body{color:red}a{color:blue}",
33 | }
34 | `;
35 |
36 | exports[`parallel option should match snapshot for the "true" value and the number of files is less than the number of cores: errors 1`] = `[]`;
37 |
38 | exports[`parallel option should match snapshot for the "true" value and the number of files is less than the number of cores: warnings 1`] = `[]`;
39 |
40 | exports[`parallel option should match snapshot for the "true" value and the number of files is more than the number of cores: assets 1`] = `
41 | {
42 | "eight.css": "body{color:red}a{color:blue}",
43 | "five.css": "body{color:red}a{color:blue}",
44 | "four.css": "body{color:red}a{color:blue}",
45 | "one.css": "body{color:red}a{color:blue}",
46 | "seven.css": "body{color:red}a{color:blue}",
47 | "six.css": "body{color:red}a{color:blue}",
48 | "three.css": "body{color:red}a{color:blue}",
49 | "two.css": "body{color:red}a{color:blue}",
50 | }
51 | `;
52 |
53 | exports[`parallel option should match snapshot for the "true" value and the number of files is more than the number of cores: errors 1`] = `[]`;
54 |
55 | exports[`parallel option should match snapshot for the "true" value and the number of files is more than the number of cores: warnings 1`] = `[]`;
56 |
57 | exports[`parallel option should match snapshot for the "true" value and the number of files is same than the number of cores: assets 1`] = `
58 | {
59 | "entry-0.css": "body{color:red}a{color:blue}",
60 | "entry-1.css": "body{color:red}a{color:blue}",
61 | "entry-2.css": "body{color:red}a{color:blue}",
62 | "entry-3.css": "body{color:red}a{color:blue}",
63 | }
64 | `;
65 |
66 | exports[`parallel option should match snapshot for the "true" value and the number of files is same than the number of cores: errors 1`] = `[]`;
67 |
68 | exports[`parallel option should match snapshot for the "true" value and the number of files is same than the number of cores: warnings 1`] = `[]`;
69 |
70 | exports[`parallel option should match snapshot for the "true" value when only one file passed: assets 1`] = `
71 | {
72 | "main.css": "body{color:red}a{color:blue}",
73 | }
74 | `;
75 |
76 | exports[`parallel option should match snapshot for the "true" value when only one file passed: errors 1`] = `[]`;
77 |
78 | exports[`parallel option should match snapshot for the "true" value when only one file passed: warnings 1`] = `[]`;
79 |
80 | exports[`parallel option should match snapshot for the "true" value: assets 1`] = `
81 | {
82 | "four.css": "body{color:red}a{color:blue}",
83 | "one.css": "body{color:red}a{color:blue}",
84 | "three.css": "body{color:red}a{color:blue}",
85 | "two.css": "body{color:red}a{color:blue}",
86 | }
87 | `;
88 |
89 | exports[`parallel option should match snapshot for the "true" value: errors 1`] = `[]`;
90 |
91 | exports[`parallel option should match snapshot for the "true" value: warnings 1`] = `[]`;
92 |
93 | exports[`parallel option should match snapshot for the "undefined" value: assets 1`] = `
94 | {
95 | "four.css": "body{color:red}a{color:blue}",
96 | "one.css": "body{color:red}a{color:blue}",
97 | "three.css": "body{color:red}a{color:blue}",
98 | "two.css": "body{color:red}a{color:blue}",
99 | }
100 | `;
101 |
102 | exports[`parallel option should match snapshot for the "undefined" value: errors 1`] = `[]`;
103 |
104 | exports[`parallel option should match snapshot for the "undefined" value: warnings 1`] = `[]`;
105 |
106 | exports[`parallel option should match snapshot when a value is not specify: assets 1`] = `
107 | {
108 | "four.css": "body{color:red}a{color:blue}",
109 | "one.css": "body{color:red}a{color:blue}",
110 | "three.css": "body{color:red}a{color:blue}",
111 | "two.css": "body{color:red}a{color:blue}",
112 | }
113 | `;
114 |
115 | exports[`parallel option should match snapshot when a value is not specify: errors 1`] = `[]`;
116 |
117 | exports[`parallel option should match snapshot when a value is not specify: warnings 1`] = `[]`;
118 |
--------------------------------------------------------------------------------
/test/__snapshots__/sourceMap-option.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`when applied with "sourceMap" option should work and emit warning on valid sourcemap and minimizer error: errors 1`] = `
4 | [
5 | "Error: broken-source-map.css from Css Minimizer plugin
6 | error-plugin: /broken-source-map.css:1:7: Postcss error [test:1,5][broken-source-map.css:1,7]",
7 | "Error: dist/entry2.css from Css Minimizer plugin
8 | error-plugin: /dist/entry2.css:10:3: Postcss error [webpack://./sourcemap/foo.css:8,2][dist/entry2.css:10,3]",
9 | ]
10 | `;
11 |
12 | exports[`when applied with "sourceMap" option should work and emit warning on valid sourcemap and minimizer error: warnings 1`] = `[]`;
13 |
14 | exports[`when applied with "sourceMap" option should work and emit warnings on broken sourcemaps: assets 1`] = `
15 | {
16 | "broken-source-map.css": ".bar{color:red};",
17 | "dist/entry2.css": "body{color:red;font-weight:700}body a{text-align:center}
18 | /*# sourceMappingURL=entry2.css.map*/",
19 | "dist/entry2.css.map": {
20 | "version": 3,
21 | "file": "dist/entry2.css",
22 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAIA,OACE,iBAGF",
23 | "sources": [
24 | "webpack:///./sourcemap/bar.scss",
25 | "webpack:///./sourcemap/foo.css"
26 | ],
27 | "sourcesContent": [
28 | "body {\\n font-weight: bold;\\n}",
29 | "@import 'bar';\\n\\nbody {\\n color: red;\\n}\\n\\nbody a {\\n text-align: center;\\n}"
30 | ],
31 | "names": [],
32 | "sourceRoot": ""
33 | },
34 | }
35 | `;
36 |
37 | exports[`when applied with "sourceMap" option should work and emit warnings on broken sourcemaps: errors 1`] = `[]`;
38 |
39 | exports[`when applied with "sourceMap" option should work and emit warnings on broken sourcemaps: warnings 1`] = `
40 | [
41 | "Error: broken-source-map.css contains invalid source map",
42 | ]
43 | `;
44 |
45 | exports[`when applied with "sourceMap" option should work with SourceMapDevToolPlugin plugin): assets 1`] = `
46 | {
47 | "dist/entry.css": "body{color:red;font-weight:700}body a{text-align:center}
48 | /*# sourceMappingURL=https://example.com/project/sourcemaps/entry.css.map*/",
49 | "dist/entry2.css": "body{color:red;font-weight:700}body a{text-align:center}
50 | /*# sourceMappingURL=https://example.com/project/sourcemaps/entry2.css.map*/",
51 | "sourcemaps/entry.css.map": {
52 | "version": 3,
53 | "file": "dist/entry.css",
54 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAEE,OACE,iBAIJ",
55 | "sources": [
56 | "webpack:///./sourcemap/bar.scss",
57 | "webpack:///./sourcemap/foo.scss"
58 | ],
59 | "sourcesContent": [
60 | "body {\\n font-weight: bold;\\n}",
61 | "@import 'bar';\\n\\nbody {\\n color: red;\\n a {\\n text-align: center;\\n }\\n}"
62 | ],
63 | "names": [],
64 | "sourceRoot": ""
65 | },
66 | "sourcemaps/entry2.css.map": {
67 | "version": 3,
68 | "file": "dist/entry2.css",
69 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAIA,OACE,iBAGF",
70 | "sources": [
71 | "webpack:///./sourcemap/bar.scss",
72 | "webpack:///./sourcemap/foo.css"
73 | ],
74 | "sourcesContent": [
75 | "body {\\n font-weight: bold;\\n}",
76 | "@import 'bar';\\n\\nbody {\\n color: red;\\n}\\n\\nbody a {\\n text-align: center;\\n}"
77 | ],
78 | "names": [],
79 | "sourceRoot": ""
80 | },
81 | }
82 | `;
83 |
84 | exports[`when applied with "sourceMap" option should work with SourceMapDevToolPlugin plugin): errors 1`] = `[]`;
85 |
86 | exports[`when applied with "sourceMap" option should work with SourceMapDevToolPlugin plugin): warnings 1`] = `[]`;
87 |
88 | exports[`when applied with "sourceMap" option should work with the "devtool" option and the "parallel" option with "false" value: assets 1`] = `
89 | {
90 | "entry.css": "body{color:red;font-weight:700}body a{text-align:center}
91 | /*# sourceMappingURL=entry.css.map*/",
92 | "entry.css.map": {
93 | "version": 3,
94 | "file": "entry.css",
95 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAEE,OACE,iBAIJ",
96 | "sources": [
97 | "webpack:///./sourcemap/bar.scss",
98 | "webpack:///./sourcemap/foo.scss"
99 | ],
100 | "sourcesContent": [
101 | "body {\\n font-weight: bold;\\n}",
102 | "@import 'bar';\\n\\nbody {\\n color: red;\\n a {\\n text-align: center;\\n }\\n}"
103 | ],
104 | "names": [],
105 | "sourceRoot": ""
106 | },
107 | "entry2.css": "body{color:red;font-weight:700}body a{text-align:center}
108 | /*# sourceMappingURL=entry2.css.map*/",
109 | "entry2.css.map": {
110 | "version": 3,
111 | "file": "entry2.css",
112 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAIA,OACE,iBAGF",
113 | "sources": [
114 | "webpack:///./sourcemap/bar.scss",
115 | "webpack:///./sourcemap/foo.css"
116 | ],
117 | "sourcesContent": [
118 | "body {\\n font-weight: bold;\\n}",
119 | "@import 'bar';\\n\\nbody {\\n color: red;\\n}\\n\\nbody a {\\n text-align: center;\\n}"
120 | ],
121 | "names": [],
122 | "sourceRoot": ""
123 | },
124 | }
125 | `;
126 |
127 | exports[`when applied with "sourceMap" option should work with the "devtool" option and the "parallel" option with "false" value: errors 1`] = `[]`;
128 |
129 | exports[`when applied with "sourceMap" option should work with the "devtool" option and the "parallel" option with "false" value: warnings 1`] = `[]`;
130 |
131 | exports[`when applied with "sourceMap" option should work with the "devtool" option and the "parallel" option with "true" value: assets 1`] = `
132 | {
133 | "entry.css": "body{color:red;font-weight:700}body a{text-align:center}
134 | /*# sourceMappingURL=entry.css.map*/",
135 | "entry.css.map": {
136 | "version": 3,
137 | "file": "entry.css",
138 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAEE,OACE,iBAIJ",
139 | "sources": [
140 | "webpack:///./sourcemap/bar.scss",
141 | "webpack:///./sourcemap/foo.scss"
142 | ],
143 | "sourcesContent": [
144 | "body {\\n font-weight: bold;\\n}",
145 | "@import 'bar';\\n\\nbody {\\n color: red;\\n a {\\n text-align: center;\\n }\\n}"
146 | ],
147 | "names": [],
148 | "sourceRoot": ""
149 | },
150 | "entry2.css": "body{color:red;font-weight:700}body a{text-align:center}
151 | /*# sourceMappingURL=entry2.css.map*/",
152 | "entry2.css.map": {
153 | "version": 3,
154 | "file": "entry2.css",
155 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAIA,OACE,iBAGF",
156 | "sources": [
157 | "webpack:///./sourcemap/bar.scss",
158 | "webpack:///./sourcemap/foo.css"
159 | ],
160 | "sourcesContent": [
161 | "body {\\n font-weight: bold;\\n}",
162 | "@import 'bar';\\n\\nbody {\\n color: red;\\n}\\n\\nbody a {\\n text-align: center;\\n}"
163 | ],
164 | "names": [],
165 | "sourceRoot": ""
166 | },
167 | }
168 | `;
169 |
170 | exports[`when applied with "sourceMap" option should work with the "devtool" option and the "parallel" option with "true" value: errors 1`] = `[]`;
171 |
172 | exports[`when applied with "sourceMap" option should work with the "devtool" option and the "parallel" option with "true" value: warnings 1`] = `[]`;
173 |
174 | exports[`when applied with "sourceMap" option should work with the "devtool" option: assets 1`] = `
175 | {
176 | "entry.css": "body{color:red;font-weight:700}body a{text-align:center}
177 | /*# sourceMappingURL=entry.css.map*/",
178 | "entry.css.map": {
179 | "version": 3,
180 | "file": "entry.css",
181 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAEE,OACE,iBAIJ",
182 | "sources": [
183 | "webpack:///./sourcemap/bar.scss",
184 | "webpack:///./sourcemap/foo.scss"
185 | ],
186 | "sourcesContent": [
187 | "body {\\n font-weight: bold;\\n}",
188 | "@import 'bar';\\n\\nbody {\\n color: red;\\n a {\\n text-align: center;\\n }\\n}"
189 | ],
190 | "names": [],
191 | "sourceRoot": ""
192 | },
193 | "entry2.css": "body{color:red;font-weight:700}body a{text-align:center}
194 | /*# sourceMappingURL=entry2.css.map*/",
195 | "entry2.css.map": {
196 | "version": 3,
197 | "file": "entry2.css",
198 | "mappings": "AAAA,KCGE,SAAU,CDFV,eCCF,CAIA,OACE,iBAGF",
199 | "sources": [
200 | "webpack:///./sourcemap/bar.scss",
201 | "webpack:///./sourcemap/foo.css"
202 | ],
203 | "sourcesContent": [
204 | "body {\\n font-weight: bold;\\n}",
205 | "@import 'bar';\\n\\nbody {\\n color: red;\\n}\\n\\nbody a {\\n text-align: center;\\n}"
206 | ],
207 | "names": [],
208 | "sourceRoot": ""
209 | },
210 | }
211 | `;
212 |
213 | exports[`when applied with "sourceMap" option should work with the "devtool" option: errors 1`] = `[]`;
214 |
215 | exports[`when applied with "sourceMap" option should work with the "devtool" option: warnings 1`] = `[]`;
216 |
--------------------------------------------------------------------------------
/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 | "bar1.css": "body{color:red;font-size:20px}a{color:blue}",
6 | "bar2.css": "h1{color:green}h2{color:#ff0}",
7 | "foo.css": "a {
8 | text-align: center;
9 | }
10 |
11 | ",
12 | }
13 | `;
14 |
15 | exports[`when applied with "test" option matches snapshot for a single "test" value (RegExp): errors 1`] = `[]`;
16 |
17 | exports[`when applied with "test" option matches snapshot for a single "test" value (RegExp): warnings 1`] = `[]`;
18 |
19 | exports[`when applied with "test" option matches snapshot for multiple "test" value (RegExp): assets 1`] = `
20 | {
21 | "bar1.css": "body{color:red;font-size:20px}a{color:blue}",
22 | "bar2.css": "h1{color:green}h2{color:#ff0}",
23 | "foo.css": "a {
24 | text-align: center;
25 | }
26 |
27 | ",
28 | }
29 | `;
30 |
31 | exports[`when applied with "test" option matches snapshot for multiple "test" value (RegExp): errors 1`] = `[]`;
32 |
33 | exports[`when applied with "test" option matches snapshot for multiple "test" value (RegExp): warnings 1`] = `[]`;
34 |
35 | exports[`when applied with "test" option matches snapshot with empty value: assets 1`] = `
36 | {
37 | "bar1.css": "body{color:red;font-size:20px}a{color:blue}",
38 | "bar2.css": "h1{color:green}h2{color:#ff0}",
39 | "foo.css": "a{text-align:center}",
40 | }
41 | `;
42 |
43 | exports[`when applied with "test" option matches snapshot with empty value: errors 1`] = `[]`;
44 |
45 | exports[`when applied with "test" option matches snapshot with empty value: warnings 1`] = `[]`;
46 |
--------------------------------------------------------------------------------
/test/__snapshots__/validate-options.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`validation 1`] = `
4 | "Invalid options object. Css 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-contrib/css-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 2`] = `
21 | "Invalid options object. Css 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-contrib/css-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 3`] = `
36 | "Invalid options object. Css 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-contrib/css-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 4`] = `
53 | "Invalid options object. Css 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-contrib/css-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 5`] = `
68 | "Invalid options object. Css 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-contrib/css-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 6`] = `
85 | "Invalid options object. Css 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-contrib/css-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 7`] = `
100 | "Invalid options object. Css Minimizer Plugin has been initialized using an options object that does not match the API schema.
101 | - options.minimizerOptions should be one of these:
102 | object { … } | [object { … }, ...] (should not have fewer than 1 item)
103 | -> Options for \`cssMinimizerOptions\`.
104 | -> Read more at https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#minimizeroptions
105 | Details:
106 | * options.minimizerOptions should be an object:
107 | object { … }
108 | * options.minimizerOptions should be an array:
109 | [object { … }, ...] (should not have fewer than 1 item)"
110 | `;
111 |
112 | exports[`validation 8`] = `
113 | "Invalid options object. Css Minimizer Plugin has been initialized using an options object that does not match the API schema.
114 | - options.parallel should be one of these:
115 | boolean | integer
116 | -> Use multi-process parallel running to improve the build speed.
117 | -> Read more at https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#parallel
118 | Details:
119 | * options.parallel should be a boolean.
120 | * options.parallel should be an integer."
121 | `;
122 |
123 | exports[`validation 9`] = `
124 | "Invalid options object. Css Minimizer Plugin has been initialized using an options object that does not match the API schema.
125 | - options.parallel should be one of these:
126 | boolean | integer
127 | -> Use multi-process parallel running to improve the build speed.
128 | -> Read more at https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#parallel
129 | Details:
130 | * options.parallel should be a boolean.
131 | * options.parallel should be an integer."
132 | `;
133 |
134 | exports[`validation 10`] = `
135 | "Invalid options object. Css Minimizer Plugin has been initialized using an options object that does not match the API schema.
136 | - options.minify should be one of these:
137 | function | [function, ...] (should not have fewer than 1 item)
138 | -> Allows you to override default minify function.
139 | -> Read more at https://github.com/webpack-contrib/css-minimizer-webpack-plugin/#minify
140 | Details:
141 | * options.minify should be an instance of function.
142 | * options.minify should be an array:
143 | [function, ...] (should not have fewer than 1 item)"
144 | `;
145 |
146 | exports[`validation 11`] = `
147 | "Invalid options object. Css Minimizer Plugin has been initialized using an options object that does not match the API schema.
148 | - options has an unknown property 'unknown'. These properties are valid:
149 | object { test?, include?, exclude?, minimizerOptions?, parallel?, warningsFilter?, minify? }"
150 | `;
151 |
--------------------------------------------------------------------------------
/test/__snapshots__/warningsFilter-option.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`warningsFilter option should match snapshot for a "function" value: assets 1`] = `
4 | {
5 | "bar1.css": "body {
6 | color: red;
7 | }
8 | body {
9 | color: red;
10 | font-size: 20px;
11 | }
12 | a {
13 | color: blue;
14 | }
15 |
16 | ",
17 | "bar2.css": "h1 {
18 | color: green;
19 | }
20 | h2 {
21 | color: yellow;
22 | }
23 | h3 {
24 | }
25 |
26 | ",
27 | "foo.css": "a {
28 | text-align: center;
29 | }
30 |
31 | ",
32 | }
33 | `;
34 |
35 | exports[`warningsFilter option should match snapshot for a "function" value: errors 1`] = `[]`;
36 |
37 | exports[`warningsFilter option should match snapshot for a "function" value: warnings 1`] = `
38 | [
39 | "Warning: bar1.css from Css Minimizer plugin
40 | [warning-plugin] Warning from bar1.css",
41 | "Warning: bar2.css from Css Minimizer plugin
42 | [warning-plugin] Warning from bar2.css",
43 | ]
44 | `;
45 |
--------------------------------------------------------------------------------
/test/__snapshots__/worker.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`worker should emit error: error 1`] = `
4 | [
5 | "/entry.css:1:1: Unknown word",
6 | ]
7 | `;
8 |
9 | exports[`worker should minify css: result 1`] = `
10 | {
11 | "errors": [],
12 | "outputs": [
13 | {
14 | "code": ".foo{color:red}.bar{color:coral}",
15 | "map": {
16 | "file": "entry.css",
17 | "mappings": "AAAA,KAAK,SAAU,CACf,KAAK,WAAY",
18 | "names": [],
19 | "sources": [
20 | "entry.css",
21 | ],
22 | "sourcesContent": [
23 | ".foo{color:red;}
24 | .bar{color:coral;}",
25 | ],
26 | "version": 3,
27 | },
28 | },
29 | ],
30 | "warnings": [],
31 | }
32 | `;
33 |
34 | exports[`worker should work inputSourceMap as prev: result 1`] = `
35 | {
36 | "errors": [],
37 | "outputs": [
38 | {
39 | "code": ".foo{color:red}.bar{color:coral}",
40 | "map": {
41 | "file": "entry.css",
42 | "mappings": "AAAA,KAAK,SAAU,CACf,KAAK,WAAY",
43 | "names": [],
44 | "sources": [
45 | "entry.css",
46 | ],
47 | "sourcesContent": [
48 | ".foo{color:red;}
49 | .bar{color:coral;}",
50 | ],
51 | "version": 3,
52 | },
53 | },
54 | ],
55 | "warnings": [],
56 | }
57 | `;
58 |
59 | exports[`worker should work options.minify function: result 1`] = `
60 | {
61 | "errors": [],
62 | "outputs": [
63 | {
64 | "code": ".minify {};",
65 | "map": undefined,
66 | },
67 | ],
68 | "warnings": [],
69 | }
70 | `;
71 |
--------------------------------------------------------------------------------
/test/cache-option.test.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 |
3 | import del from "del";
4 |
5 | import CssMinimizerPlugin from "../src/index";
6 |
7 | import {
8 | compile,
9 | getCompiler,
10 | getErrors,
11 | getWarnings,
12 | readAssets,
13 | } from "./helpers";
14 |
15 | describe('"cache" option', () => {
16 | const fileSystemCacheDirectory = path.resolve(
17 | __dirname,
18 | "./outputs/type-filesystem",
19 | );
20 | const fileSystemCacheDirectory1 = path.resolve(
21 | __dirname,
22 | "./outputs/type-filesystem-1",
23 | );
24 | const fileSystemCacheDirectory2 = path.resolve(
25 | __dirname,
26 | "./outputs/type-filesystem-2",
27 | );
28 |
29 | beforeAll(() =>
30 | Promise.all([
31 | del(fileSystemCacheDirectory),
32 | del(fileSystemCacheDirectory1),
33 | del(fileSystemCacheDirectory2),
34 | ]),
35 | );
36 |
37 | it('should work with the "false" value for the "cache" option', async () => {
38 | const compiler = getCompiler({
39 | entry: {
40 | one: `${__dirname}/fixtures/cache.js`,
41 | two: `${__dirname}/fixtures/cache-1.js`,
42 | three: `${__dirname}/fixtures/cache-2.js`,
43 | four: `${__dirname}/fixtures/cache-3.js`,
44 | five: `${__dirname}/fixtures/cache-4.js`,
45 | },
46 | cache: false,
47 | });
48 |
49 | new CssMinimizerPlugin().apply(compiler);
50 |
51 | let getCounter = 0;
52 |
53 | compiler.cache.hooks.get.tap(
54 | { name: "TestCache", stage: -100 },
55 | (identifier) => {
56 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
57 | getCounter += 1;
58 | }
59 | },
60 | );
61 |
62 | let storeCounter = 0;
63 |
64 | compiler.cache.hooks.store.tap(
65 | { name: "TestCache", stage: -100 },
66 | (identifier) => {
67 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
68 | storeCounter += 1;
69 | }
70 | },
71 | );
72 |
73 | const stats = await compile(compiler);
74 |
75 | // Without cache webpack always try to get
76 | expect(getCounter).toBe(5);
77 | // Without cache webpack always try to store
78 | expect(storeCounter).toBe(5);
79 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
80 | expect(getErrors(stats)).toMatchSnapshot("errors");
81 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
82 |
83 | getCounter = 0;
84 | storeCounter = 0;
85 |
86 | const newStats = await compile(compiler);
87 |
88 | // Without cache webpack always try to get
89 | expect(getCounter).toBe(5);
90 | // Without cache webpack always try to store
91 | expect(storeCounter).toBe(5);
92 | expect(readAssets(compiler, newStats, /\.css$/)).toMatchSnapshot("assets");
93 | expect(getErrors(newStats)).toMatchSnapshot("errors");
94 | expect(getWarnings(newStats)).toMatchSnapshot("warnings");
95 |
96 | await new Promise((resolve) => {
97 | compiler.close(() => {
98 | resolve();
99 | });
100 | });
101 | });
102 |
103 | it('should work with the "memory" value for the "cache.type" option', async () => {
104 | const compiler = getCompiler({
105 | entry: {
106 | one: `${__dirname}/fixtures/cache.js`,
107 | two: `${__dirname}/fixtures/cache-1.js`,
108 | three: `${__dirname}/fixtures/cache-2.js`,
109 | four: `${__dirname}/fixtures/cache-3.js`,
110 | five: `${__dirname}/fixtures/cache-4.js`,
111 | },
112 | cache: {
113 | type: "memory",
114 | },
115 | });
116 |
117 | new CssMinimizerPlugin().apply(compiler);
118 |
119 | let getCounter = 0;
120 |
121 | compiler.cache.hooks.get.tap(
122 | { name: "TestCache", stage: -100 },
123 | (identifier) => {
124 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
125 | getCounter += 1;
126 | }
127 | },
128 | );
129 |
130 | let storeCounter = 0;
131 |
132 | compiler.cache.hooks.store.tap(
133 | { name: "TestCache", stage: -100 },
134 | (identifier) => {
135 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
136 | storeCounter += 1;
137 | }
138 | },
139 | );
140 |
141 | const stats = await compile(compiler);
142 |
143 | // Get cache for assets
144 | expect(getCounter).toBe(5);
145 | // Store cached assets
146 | expect(storeCounter).toBe(5);
147 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
148 | expect(getErrors(stats)).toMatchSnapshot("errors");
149 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
150 |
151 | getCounter = 0;
152 | storeCounter = 0;
153 |
154 | const newStats = await compile(compiler);
155 |
156 | // Get cache for assets
157 | expect(getCounter).toBe(5);
158 | // No need to store, we got cached assets
159 | expect(storeCounter).toBe(0);
160 | expect(readAssets(compiler, newStats, /\.css$/)).toMatchSnapshot("assets");
161 | expect(getErrors(newStats)).toMatchSnapshot("errors");
162 | expect(getWarnings(newStats)).toMatchSnapshot("warnings");
163 |
164 | await new Promise((resolve) => {
165 | compiler.close(() => {
166 | resolve();
167 | });
168 | });
169 | });
170 |
171 | it('should work with the "filesystem" value for the "cache.type" option', async () => {
172 | const compiler = getCompiler({
173 | entry: {
174 | one: `${__dirname}/fixtures/cache.js`,
175 | two: `${__dirname}/fixtures/cache-1.js`,
176 | three: `${__dirname}/fixtures/cache-2.js`,
177 | four: `${__dirname}/fixtures/cache-3.js`,
178 | five: `${__dirname}/fixtures/cache-4.js`,
179 | },
180 | cache: {
181 | type: "filesystem",
182 | cacheDirectory: fileSystemCacheDirectory,
183 | },
184 | });
185 |
186 | new CssMinimizerPlugin().apply(compiler);
187 |
188 | let getCounter = 0;
189 |
190 | compiler.cache.hooks.get.tap(
191 | { name: "TestCache", stage: -100 },
192 | (identifier) => {
193 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
194 | getCounter += 1;
195 | }
196 | },
197 | );
198 |
199 | let storeCounter = 0;
200 |
201 | compiler.cache.hooks.store.tap(
202 | { name: "TestCache", stage: -100 },
203 | (identifier) => {
204 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
205 | storeCounter += 1;
206 | }
207 | },
208 | );
209 |
210 | const stats = await compile(compiler);
211 |
212 | // Get cache for assets
213 | expect(getCounter).toBe(5);
214 | // Store cached assets
215 | expect(storeCounter).toBe(5);
216 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
217 | expect(getErrors(stats)).toMatchSnapshot("errors");
218 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
219 |
220 | getCounter = 0;
221 | storeCounter = 0;
222 |
223 | const newStats = await compile(compiler);
224 |
225 | // Get cache for assets
226 | expect(getCounter).toBe(5);
227 | // No need to store, we got cached assets
228 | expect(storeCounter).toBe(0);
229 | expect(readAssets(compiler, newStats, /\.css$/)).toMatchSnapshot("assets");
230 | expect(getErrors(newStats)).toMatchSnapshot("errors");
231 | expect(getWarnings(newStats)).toMatchSnapshot("warnings");
232 |
233 | await new Promise((resolve) => {
234 | compiler.close(() => {
235 | resolve();
236 | });
237 | });
238 | });
239 |
240 | it('should work with the "filesystem" value for the "cache.type" option and source maps', async () => {
241 | const compiler = getCompiler({
242 | devtool: "source-map",
243 | entry: {
244 | one: path.resolve(__dirname, "./fixtures/cache.js"),
245 | two: path.resolve(__dirname, "./fixtures/cache-1.js"),
246 | three: path.resolve(__dirname, "./fixtures/cache-2.js"),
247 | four: path.resolve(__dirname, "./fixtures/cache-3.js"),
248 | five: path.resolve(__dirname, "./fixtures/cache-4.js"),
249 | },
250 | cache: {
251 | type: "filesystem",
252 | cacheDirectory: fileSystemCacheDirectory1,
253 | },
254 | });
255 |
256 | new CssMinimizerPlugin().apply(compiler);
257 |
258 | let getCounter = 0;
259 |
260 | compiler.cache.hooks.get.tap(
261 | { name: "TestCache", stage: -100 },
262 | (identifier) => {
263 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
264 | getCounter += 1;
265 | }
266 | },
267 | );
268 |
269 | let storeCounter = 0;
270 |
271 | compiler.cache.hooks.store.tap(
272 | { name: "TestCache", stage: -100 },
273 | (identifier) => {
274 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
275 | storeCounter += 1;
276 | }
277 | },
278 | );
279 |
280 | const stats = await compile(compiler);
281 |
282 | // Get cache for assets
283 | expect(getCounter).toBe(5);
284 | // Store cached assets
285 | expect(storeCounter).toBe(5);
286 | expect(readAssets(compiler, stats, /\.css(\.map)?$/)).toMatchSnapshot(
287 | "assets",
288 | );
289 | expect(getErrors(stats)).toMatchSnapshot("errors");
290 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
291 |
292 | getCounter = 0;
293 | storeCounter = 0;
294 |
295 | const newStats = await compile(compiler);
296 |
297 | // Get cache for assets
298 | expect(getCounter).toBe(5);
299 | // No need to store, we got cached assets
300 | expect(storeCounter).toBe(0);
301 | expect(readAssets(compiler, newStats, /\.css(\.map)?$/)).toMatchSnapshot(
302 | "assets",
303 | );
304 | expect(getErrors(newStats)).toMatchSnapshot("errors");
305 | expect(getWarnings(newStats)).toMatchSnapshot("warnings");
306 |
307 | await new Promise((resolve) => {
308 | compiler.close(() => {
309 | resolve();
310 | });
311 | });
312 | });
313 |
314 | it('should work with the "filesystem" value for the "cache.type" option and output warnings', async () => {
315 | const compiler = getCompiler({
316 | entry: {
317 | one: path.resolve(__dirname, "./fixtures/cache.js"),
318 | two: path.resolve(__dirname, "./fixtures/cache-1.js"),
319 | three: path.resolve(__dirname, "./fixtures/cache-2.js"),
320 | four: path.resolve(__dirname, "./fixtures/cache-3.js"),
321 | five: path.resolve(__dirname, "./fixtures/cache-4.js"),
322 | },
323 | cache: {
324 | type: "filesystem",
325 | cacheDirectory: fileSystemCacheDirectory2,
326 | },
327 | });
328 |
329 | new CssMinimizerPlugin({
330 | minify: (data) => {
331 | // eslint-disable-next-line global-require
332 | const postcss = require("postcss");
333 | const [[fileName, input]] = Object.entries(data);
334 | const plugin = () => {
335 | return {
336 | postcssPlugin: "warning-plugin",
337 | OnceExit(decl, { result }) {
338 | result.warn(`Warning from ${result.opts.from}`, {
339 | plugin: "warning-plugin",
340 | });
341 | },
342 | };
343 | };
344 |
345 | plugin.postcss = true;
346 |
347 | return postcss([plugin])
348 | .process(input, { from: fileName, to: fileName })
349 | .then((result) => {
350 | return {
351 | code: result.css,
352 | map: result.map,
353 | error: result.error,
354 | warnings: result.warnings(),
355 | };
356 | });
357 | },
358 | }).apply(compiler);
359 |
360 | let getCounter = 0;
361 |
362 | compiler.cache.hooks.get.tap(
363 | { name: "TestCache", stage: -100 },
364 | (identifier) => {
365 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
366 | getCounter += 1;
367 | }
368 | },
369 | );
370 |
371 | let storeCounter = 0;
372 |
373 | compiler.cache.hooks.store.tap(
374 | { name: "TestCache", stage: -100 },
375 | (identifier) => {
376 | if (identifier.indexOf("CssMinimizerWebpackPlugin") !== -1) {
377 | storeCounter += 1;
378 | }
379 | },
380 | );
381 |
382 | const stats = await compile(compiler);
383 |
384 | // Get cache for assets
385 | expect(getCounter).toBe(5);
386 | // Store cached assets
387 | expect(storeCounter).toBe(5);
388 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
389 | expect(getErrors(stats)).toMatchSnapshot("errors");
390 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
391 |
392 | getCounter = 0;
393 | storeCounter = 0;
394 |
395 | const newStats = await compile(compiler);
396 |
397 | // Get cache for assets
398 | expect(getCounter).toBe(5);
399 | // No need to store, we got cached assets
400 | expect(storeCounter).toBe(0);
401 | expect(readAssets(compiler, newStats, /\.css$/)).toMatchSnapshot("assets");
402 | expect(getErrors(newStats)).toMatchSnapshot("errors");
403 | expect(getWarnings(newStats)).toMatchSnapshot("warnings");
404 |
405 | await new Promise((resolve) => {
406 | compiler.close(() => {
407 | resolve();
408 | });
409 | });
410 | });
411 | });
412 |
--------------------------------------------------------------------------------
/test/exclude-option.test.js:
--------------------------------------------------------------------------------
1 | import CssMinimizerPlugin 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 | compiler = getCompiler({
16 | entry: {
17 | excluded1: `${__dirname}/fixtures/excluded1.js`,
18 | excluded2: `${__dirname}/fixtures/excluded2.js`,
19 | entry: `${__dirname}/fixtures/entry.js`,
20 | },
21 | });
22 | });
23 |
24 | it("should match snapshot for a single RegExp value excluded1", async () => {
25 | new CssMinimizerPlugin({
26 | exclude: /excluded1/i,
27 | }).apply(compiler);
28 |
29 | const stats = await compile(compiler);
30 |
31 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
32 | expect(getErrors(stats)).toMatchSnapshot("errors");
33 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
34 | });
35 |
36 | it("should match snapshot for a single String value excluded1", async () => {
37 | new CssMinimizerPlugin({
38 | exclude: "excluded1",
39 | }).apply(compiler);
40 |
41 | const stats = await compile(compiler);
42 |
43 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
44 | expect(getErrors(stats)).toMatchSnapshot("errors");
45 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
46 | });
47 |
48 | it("should match snapshot for multiple RegExp values excluded1 and excluded2", async () => {
49 | new CssMinimizerPlugin({
50 | exclude: [/excluded1/i, /excluded2/i],
51 | }).apply(compiler);
52 |
53 | const stats = await compile(compiler);
54 |
55 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
56 | expect(getErrors(stats)).toMatchSnapshot("errors");
57 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
58 | });
59 |
60 | it("should match snapshot for multiple String values excluded1 and excluded2", async () => {
61 | new CssMinimizerPlugin({
62 | exclude: ["excluded1", "excluded2"],
63 | }).apply(compiler);
64 |
65 | const stats = await compile(compiler);
66 |
67 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
68 | expect(getErrors(stats)).toMatchSnapshot("errors");
69 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/test/fixtures/cache-1.js:
--------------------------------------------------------------------------------
1 | import './test/foo.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/cache-2.js:
--------------------------------------------------------------------------------
1 | import './test/bar1.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/cache-3.js:
--------------------------------------------------------------------------------
1 | import './test/bar2.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/cache-4.js:
--------------------------------------------------------------------------------
1 | import './test/bar1.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/cache.js:
--------------------------------------------------------------------------------
1 | import './test/foo.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/entry.js:
--------------------------------------------------------------------------------
1 | import './foo.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/excluded1.js:
--------------------------------------------------------------------------------
1 | import './test/foo.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/excluded2.js:
--------------------------------------------------------------------------------
1 | import './test/bar1.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/foo.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: red;
3 | }
4 | a {
5 | color: blue;
6 | }
--------------------------------------------------------------------------------
/test/fixtures/included1.js:
--------------------------------------------------------------------------------
1 | import './test/foo.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/included2.js:
--------------------------------------------------------------------------------
1 | import './test/bar1.css';
2 |
--------------------------------------------------------------------------------
/test/fixtures/minimizerOptions/discardComments.css:
--------------------------------------------------------------------------------
1 | body {
2 | /* this is a comment */
3 | /*! this is a comment with exclamation mark */
4 | color: red;
5 | }
--------------------------------------------------------------------------------
/test/fixtures/minimizerOptions/discardEmpty.css:
--------------------------------------------------------------------------------
1 | @layer ui-components, foo-bar;
2 |
3 | body {
4 | color: red;
5 | }
6 |
7 | a {
8 | }
9 |
10 | .foo {
11 | color: black;
12 |
13 | & .class {
14 | color: white;
15 | }
16 | }
17 |
18 | @layer ui-components {
19 | }
20 |
--------------------------------------------------------------------------------
/test/fixtures/minimizerOptions/mergeRules.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: red;
3 | }
4 |
5 | body {
6 | font-weight: bold;
7 | }
--------------------------------------------------------------------------------
/test/fixtures/minimizerOptions/order.css:
--------------------------------------------------------------------------------
1 | p {
2 | border: 1px solid var(--test);
3 | border-radius: var(--test);
4 | border-width: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/test/fixtures/nesting.css:
--------------------------------------------------------------------------------
1 | table.colortable {
2 | & td {
3 | text-align:center;
4 | &.c { text-transform:uppercase }
5 |
6 | &:first-child, &:first-child + td { border:1px solid black }
7 | }
8 |
9 | & th {
10 | text-align:center;
11 | background:black;
12 | color:white;
13 | }
14 | }
15 |
16 | .example {
17 | display: grid;
18 | transition: all .5s;
19 | user-select: none;
20 | background: linear-gradient(to bottom, white, black);
21 | }
22 |
--------------------------------------------------------------------------------
/test/fixtures/simple-async.js:
--------------------------------------------------------------------------------
1 | export default 'bar';
2 |
--------------------------------------------------------------------------------
/test/fixtures/simple-emit-2.js:
--------------------------------------------------------------------------------
1 | export default 'bar';
2 |
--------------------------------------------------------------------------------
/test/fixtures/simple-emit.js:
--------------------------------------------------------------------------------
1 | export default 'foo';
2 |
--------------------------------------------------------------------------------
/test/fixtures/simple.js:
--------------------------------------------------------------------------------
1 | import foo from './simple-emit';
2 | import bar from './simple-emit-2';
3 | import './foo.css';
4 |
5 | async function load() {
6 | return import('./simple-async');
7 | }
8 |
9 | load();
10 |
11 | export default [foo, bar, extracted, css, otherCss];
12 |
--------------------------------------------------------------------------------
/test/fixtures/sourcemap/bar.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-weight: bold;
3 | }
--------------------------------------------------------------------------------
/test/fixtures/sourcemap/bar.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-weight: bold;
3 | }
--------------------------------------------------------------------------------
/test/fixtures/sourcemap/foo.css:
--------------------------------------------------------------------------------
1 | @import 'bar';
2 |
3 | body {
4 | color: red;
5 | }
6 |
7 | body a {
8 | text-align: center;
9 | }
--------------------------------------------------------------------------------
/test/fixtures/sourcemap/foo.scss:
--------------------------------------------------------------------------------
1 | @import 'bar';
2 |
3 | body {
4 | color: red;
5 | a {
6 | text-align: center;
7 | }
8 | }
--------------------------------------------------------------------------------
/test/fixtures/sss/index.sss:
--------------------------------------------------------------------------------
1 | a
2 | color: black
3 |
--------------------------------------------------------------------------------
/test/fixtures/sugarss.js:
--------------------------------------------------------------------------------
1 | export const foo = 'foo';
2 |
--------------------------------------------------------------------------------
/test/fixtures/test/bar1.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: red;
3 | }
4 | body {
5 | color: red;
6 | font-size: 20px;
7 | }
8 | a {
9 | color: blue;
10 | }
11 |
--------------------------------------------------------------------------------
/test/fixtures/test/bar2.css:
--------------------------------------------------------------------------------
1 | h1 {
2 | color: green;
3 | }
4 | h2 {
5 | color: yellow;
6 | }
7 | h3 {
8 | }
9 |
--------------------------------------------------------------------------------
/test/fixtures/test/error.css:
--------------------------------------------------------------------------------
1 | null
2 |
--------------------------------------------------------------------------------
/test/fixtures/test/foo.css:
--------------------------------------------------------------------------------
1 | a {
2 | text-align: center;
3 | }
4 |
--------------------------------------------------------------------------------
/test/fixtures/wrong-calc.css:
--------------------------------------------------------------------------------
1 | width: calc(100px + 100);
2 |
--------------------------------------------------------------------------------
/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 | // eslint-disable-next-line no-param-reassign
19 | compilation.emitAsset(
20 | this.options.name,
21 | new RawSource(`
22 | .a {
23 | display: block;
24 | color: coral;
25 | }
26 | `),
27 | );
28 | },
29 | );
30 | });
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/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 { ConcatSource } = compiler.webpack.sources;
9 |
10 | compiler.hooks.thisCompilation.tap(plugin, (compilation) => {
11 | compilation.hooks.additionalAssets.tap(plugin, () => {
12 | // eslint-disable-next-line no-param-reassign
13 | compilation.assets[this.options.name] = new ConcatSource(
14 | `a { color: red; }`,
15 | compilation.assets[this.options.name],
16 | );
17 | });
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/test/helpers/compile.js:
--------------------------------------------------------------------------------
1 | export default function compile(compiler) {
2 | return new Promise((resolve, reject) => {
3 | compiler.run((err, stats) => {
4 | if (err) return reject(err);
5 | return resolve(stats);
6 | });
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/test/helpers/emitAssetInChildCompilationLoader.js:
--------------------------------------------------------------------------------
1 | class PreCopyPlugin {
2 | constructor(options = {}) {
3 | this.options = options.options || {};
4 | }
5 |
6 | // eslint-disable-next-line class-methods-use-this
7 | apply(compiler) {
8 | const plugin = { name: "PreCopyPlugin" };
9 | const { RawSource } = compiler.webpack.sources;
10 |
11 | compiler.hooks.compilation.tap(plugin, (compilation) => {
12 | compilation.hooks.additionalAssets.tapAsync(plugin, (callback) => {
13 | compilation.emitAsset(
14 | "entry.css",
15 | new RawSource(".entry {\n text-align: center;\n}\n\n"),
16 | );
17 |
18 | callback();
19 | });
20 | });
21 | }
22 | }
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/helpers/emitAssetLoader.js:
--------------------------------------------------------------------------------
1 | export default function loader(content) {
2 | this.emitFile("style.css", "a { color: red; }");
3 |
4 | const callback = this.async();
5 |
6 | return callback(null, content);
7 | }
8 |
--------------------------------------------------------------------------------
/test/helpers/emitAssetLoader2.js:
--------------------------------------------------------------------------------
1 | export default function loader(content) {
2 | this.emitFile("style-2.css", "a { color: coral; }");
3 |
4 | const callback = this.async();
5 |
6 | return callback(null, content);
7 | }
8 |
--------------------------------------------------------------------------------
/test/helpers/getCompiler.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 |
3 | import webpack from "webpack";
4 | import MiniCssExtractPlugin from "mini-css-extract-plugin";
5 | import { createFsFromVolume, Volume } from "memfs";
6 |
7 | export default function getCompiler(config) {
8 | const compiler = webpack({
9 | mode: "development",
10 | devtool: config.devtool || false,
11 | context: path.resolve(__dirname, "../fixtures"),
12 | optimization: {
13 | minimize: false,
14 | },
15 | output: {
16 | pathinfo: false,
17 | path: path.resolve(__dirname, "../outputs"),
18 | filename: "[name].js",
19 | chunkFilename: "[id].[name].js",
20 | },
21 | plugins: [
22 | new MiniCssExtractPlugin({
23 | filename: "[name].css",
24 | chunkFilename: "[id].[name].css",
25 | }),
26 | ],
27 | module: {
28 | rules: [
29 | {
30 | test: /.s?css$/i,
31 | use: [MiniCssExtractPlugin.loader, "css-loader"],
32 | },
33 | ],
34 | },
35 | ...config,
36 | });
37 |
38 | if (!config.outputFileSystem) {
39 | compiler.outputFileSystem = createFsFromVolume(new Volume());
40 | }
41 |
42 | return compiler;
43 | }
44 |
--------------------------------------------------------------------------------
/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/helpers/index.js:
--------------------------------------------------------------------------------
1 | import compile from "./compile";
2 | import getCompiler from "./getCompiler";
3 | import readAsset from "./readAsset";
4 | import readAssets from "./readAssets";
5 | import ModifyExistingAsset from "./ModifyExistingAsset";
6 | import EmitNewAsset from "./EmitNewAsset";
7 | import getErrors from "./getErrors";
8 | import getWarnings from "./getWarnings";
9 | import normalizeErrors from "./normalizeErrors";
10 |
11 | export {
12 | compile,
13 | getCompiler,
14 | readAsset,
15 | readAssets,
16 | ModifyExistingAsset,
17 | EmitNewAsset,
18 | getErrors,
19 | getWarnings,
20 | normalizeErrors,
21 | };
22 |
--------------------------------------------------------------------------------
/test/helpers/normalizeErrors.js:
--------------------------------------------------------------------------------
1 | function removeCWD(str) {
2 | const isWin = process.platform === "win32";
3 | let cwd = process.cwd();
4 |
5 | if (isWin) {
6 | // eslint-disable-next-line no-param-reassign
7 | str = str.replace(/\\/g, "/");
8 | // eslint-disable-next-line no-param-reassign
9 | cwd = cwd.replace(/\\/g, "/");
10 | }
11 |
12 | return str.replace(new RegExp(cwd, "g"), "");
13 | }
14 |
15 | export default (errors) =>
16 | errors.map((error) =>
17 | removeCWD(error.toString().split("\n").slice(0, 2).join("\n")),
18 | );
19 |
--------------------------------------------------------------------------------
/test/helpers/readAsset.js:
--------------------------------------------------------------------------------
1 | import path from "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 | export default function readAssets(compiler, stats, extension) {
4 | const assets = {};
5 |
6 | Object.keys(stats.compilation.assets).forEach((asset) => {
7 | if (typeof extension === "undefined") {
8 | assets[asset] = readAsset(asset, compiler, stats);
9 | } else if (extension.test(asset)) {
10 | assets[asset] = readAsset(asset, compiler, stats);
11 | }
12 | });
13 |
14 | return assets;
15 | }
16 |
--------------------------------------------------------------------------------
/test/include-option.test.js:
--------------------------------------------------------------------------------
1 | import CssMinimizerPlugin 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 | compiler = getCompiler({
16 | entry: {
17 | included1: `${__dirname}/fixtures/included1.js`,
18 | included2: `${__dirname}/fixtures/included2.js`,
19 | entry: `${__dirname}/fixtures/entry.js`,
20 | },
21 | });
22 | });
23 |
24 | it("should match snapshot for a single RegExp value included1", async () => {
25 | new CssMinimizerPlugin({
26 | include: /included1/i,
27 | }).apply(compiler);
28 |
29 | const stats = await compile(compiler);
30 |
31 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
32 | expect(getErrors(stats)).toMatchSnapshot("errors");
33 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
34 | });
35 |
36 | it("should match snapshot for a single String value included1", async () => {
37 | new CssMinimizerPlugin({
38 | include: "included1",
39 | }).apply(compiler);
40 |
41 | const stats = await compile(compiler);
42 |
43 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
44 | expect(getErrors(stats)).toMatchSnapshot("errors");
45 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
46 | });
47 |
48 | it("should match snapshot for multiple RegExp values included1 and included2", async () => {
49 | new CssMinimizerPlugin({
50 | include: [/included1/i, /included2/i],
51 | }).apply(compiler);
52 |
53 | const stats = await compile(compiler);
54 |
55 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
56 | expect(getErrors(stats)).toMatchSnapshot("errors");
57 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
58 | });
59 |
60 | it("should match snapshot for multiple String values included1 and included2", async () => {
61 | new CssMinimizerPlugin({
62 | include: ["included1", "included2"],
63 | }).apply(compiler);
64 |
65 | const stats = await compile(compiler);
66 |
67 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
68 | expect(getErrors(stats)).toMatchSnapshot("errors");
69 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/test/minimizerOptions-option.test.js:
--------------------------------------------------------------------------------
1 | import CopyPlugin from "copy-webpack-plugin";
2 | import MiniCssExtractPlugin from "mini-css-extract-plugin";
3 | import sugarss from "sugarss";
4 |
5 | import CssMinimizerPlugin from "../src/index";
6 |
7 | import { getCompiler, compile, readAsset } from "./helpers";
8 |
9 | describe('when applied with "minimizerOptions" option', () => {
10 | it('matches snapshot for "discardComments" option (enable [default])', () => {
11 | const compiler = getCompiler({
12 | entry: {
13 | entry: `${__dirname}/fixtures/minimizerOptions/discardComments.css`,
14 | },
15 | });
16 | new CssMinimizerPlugin().apply(compiler);
17 |
18 | return compile(compiler).then((stats) => {
19 | expect(stats.compilation.errors).toEqual([]);
20 | expect(stats.compilation.warnings).toEqual([]);
21 |
22 | for (const file in stats.compilation.assets) {
23 | // eslint-disable-next-line no-continue
24 | if (/\.js$/.test(file)) continue;
25 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
26 | }
27 | });
28 | });
29 |
30 | it('matches snapshot for "discardComments" option (disable)', () => {
31 | const compiler = getCompiler({
32 | entry: {
33 | entry: `${__dirname}/fixtures/minimizerOptions/discardComments.css`,
34 | },
35 | });
36 | new CssMinimizerPlugin({
37 | minimizerOptions: {
38 | preset: ["default", { discardComments: false }],
39 | },
40 | }).apply(compiler);
41 |
42 | return compile(compiler).then((stats) => {
43 | expect(stats.compilation.errors).toEqual([]);
44 | expect(stats.compilation.warnings).toEqual([]);
45 |
46 | for (const file in stats.compilation.assets) {
47 | // eslint-disable-next-line no-continue
48 | if (/\.js$/.test(file)) continue;
49 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
50 | }
51 | });
52 | });
53 |
54 | it('matches snapshot for "discardComments" option (enable, with "removeAll" option)', () => {
55 | const compiler = getCompiler({
56 | entry: {
57 | entry: `${__dirname}/fixtures/minimizerOptions/discardComments.css`,
58 | },
59 | });
60 | new CssMinimizerPlugin({
61 | minimizerOptions: {
62 | preset: ["default", { discardComments: { removeAll: true } }],
63 | },
64 | }).apply(compiler);
65 |
66 | return compile(compiler).then((stats) => {
67 | expect(stats.compilation.errors).toEqual([]);
68 | expect(stats.compilation.warnings).toEqual([]);
69 |
70 | for (const file in stats.compilation.assets) {
71 | // eslint-disable-next-line no-continue
72 | if (/\.js$/.test(file)) continue;
73 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
74 | }
75 | });
76 | });
77 |
78 | it('matches snapshot for "preset" option with require.resolve "String" value', () => {
79 | const compiler = getCompiler({
80 | entry: {
81 | entry: `${__dirname}/fixtures/minimizerOptions/order.css`,
82 | },
83 | });
84 | new CssMinimizerPlugin({
85 | minimizerOptions: {
86 | preset: require.resolve("cssnano-preset-default"),
87 | },
88 | }).apply(compiler);
89 |
90 | const compiler2 = getCompiler({
91 | entry: {
92 | entry: `${__dirname}/fixtures/minimizerOptions/order.css`,
93 | },
94 | });
95 | new CssMinimizerPlugin({
96 | minimizerOptions: {
97 | preset: require.resolve("cssnano-preset-default"),
98 | },
99 | }).apply(compiler2);
100 |
101 | const result1 = compile(compiler).then((stats) => {
102 | expect(stats.compilation.errors).toEqual([]);
103 | expect(stats.compilation.warnings).toEqual([]);
104 |
105 | for (const file in stats.compilation.assets) {
106 | // eslint-disable-next-line no-continue
107 | if (/\.js$/.test(file)) continue;
108 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(
109 | `default-preset`,
110 | );
111 | }
112 | });
113 |
114 | const result2 = compile(compiler2).then((stats) => {
115 | expect(stats.compilation.errors).toEqual([]);
116 | expect(stats.compilation.warnings).toEqual([]);
117 |
118 | for (const file in stats.compilation.assets) {
119 | // eslint-disable-next-line no-continue
120 | if (/\.js$/.test(file)) continue;
121 | expect(readAsset(file, compiler2, stats)).toMatchSnapshot(
122 | `preset-simple`,
123 | );
124 | }
125 | });
126 |
127 | return Promise.all([result1, result2]);
128 | });
129 |
130 | it('matches snapshot for "mergeRules" option (enable [default])', () => {
131 | const compiler = getCompiler({
132 | entry: {
133 | entry: `${__dirname}/fixtures/minimizerOptions/mergeRules.css`,
134 | },
135 | });
136 | new CssMinimizerPlugin().apply(compiler);
137 |
138 | return compile(compiler).then((stats) => {
139 | expect(stats.compilation.errors).toEqual([]);
140 | expect(stats.compilation.warnings).toEqual([]);
141 |
142 | for (const file in stats.compilation.assets) {
143 | // eslint-disable-next-line no-continue
144 | if (/\.js$/.test(file)) continue;
145 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
146 | }
147 | });
148 | });
149 |
150 | it('matches snapshot for "mergeRules" option (disable)', () => {
151 | const compiler = getCompiler({
152 | entry: {
153 | entry: `${__dirname}/fixtures/minimizerOptions/mergeRules.css`,
154 | },
155 | });
156 | new CssMinimizerPlugin({
157 | minimizerOptions: {
158 | preset: ["default", { mergeRules: false }],
159 | },
160 | }).apply(compiler);
161 |
162 | return compile(compiler).then((stats) => {
163 | expect(stats.compilation.errors).toEqual([]);
164 | expect(stats.compilation.warnings).toEqual([]);
165 |
166 | for (const file in stats.compilation.assets) {
167 | // eslint-disable-next-line no-continue
168 | if (/\.js$/.test(file)) continue;
169 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
170 | }
171 | });
172 | });
173 |
174 | it('matches snapshot for "discardEmpty" option (enable [default])', () => {
175 | const compiler = getCompiler({
176 | entry: {
177 | entry: `${__dirname}/fixtures/minimizerOptions/discardEmpty.css`,
178 | },
179 | });
180 | new CssMinimizerPlugin().apply(compiler);
181 |
182 | return compile(compiler).then((stats) => {
183 | expect(stats.compilation.errors).toEqual([]);
184 | expect(stats.compilation.warnings).toEqual([]);
185 |
186 | for (const file in stats.compilation.assets) {
187 | // eslint-disable-next-line no-continue
188 | if (/\.js$/.test(file)) continue;
189 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
190 | }
191 | });
192 | });
193 |
194 | it('matches snapshot for "discardEmpty" option (disable)', () => {
195 | const compiler = getCompiler({
196 | entry: {
197 | entry: `${__dirname}/fixtures/minimizerOptions/discardEmpty.css`,
198 | },
199 | });
200 | new CssMinimizerPlugin({
201 | minimizerOptions: {
202 | preset: ["default", { discardEmpty: false }],
203 | },
204 | }).apply(compiler);
205 |
206 | return compile(compiler).then((stats) => {
207 | expect(stats.compilation.errors).toEqual([]);
208 | expect(stats.compilation.warnings).toEqual([]);
209 |
210 | for (const file in stats.compilation.assets) {
211 | // eslint-disable-next-line no-continue
212 | if (/\.js$/.test(file)) continue;
213 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
214 | }
215 | });
216 | });
217 |
218 | it('matches snapshot for "parser" option with "Function" value', () => {
219 | const compiler = getCompiler({
220 | entry: {
221 | entry: `${__dirname}/fixtures/sugarss.js`,
222 | },
223 | module: {},
224 | plugins: [
225 | new CopyPlugin({
226 | patterns: [
227 | {
228 | context: `${__dirname}/fixtures/sss`,
229 | from: `index.sss`,
230 | },
231 | ],
232 | }),
233 | new MiniCssExtractPlugin({
234 | filename: "[name].css",
235 | }),
236 | ],
237 | });
238 | new CssMinimizerPlugin({
239 | test: /\.(css|sss)$/i,
240 | parallel: false,
241 | minimizerOptions: {
242 | processorOptions: {
243 | parser: sugarss,
244 | },
245 | },
246 | }).apply(compiler);
247 |
248 | return compile(compiler).then((stats) => {
249 | expect(stats.compilation.errors).toEqual([]);
250 | expect(stats.compilation.warnings).toEqual([]);
251 |
252 | for (const file in stats.compilation.assets) {
253 | // eslint-disable-next-line no-continue
254 | if (/\.js$/.test(file)) continue;
255 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
256 | }
257 | });
258 | });
259 |
260 | it('matches snapshot for "parser" option with "String" value', () => {
261 | const compiler = getCompiler({
262 | entry: {
263 | entry: `${__dirname}/fixtures/sugarss.js`,
264 | },
265 | module: {},
266 | plugins: [
267 | new CopyPlugin({
268 | patterns: [
269 | {
270 | context: `${__dirname}/fixtures/sss`,
271 | from: `index.sss`,
272 | },
273 | ],
274 | }),
275 | new MiniCssExtractPlugin({
276 | filename: "[name].css",
277 | }),
278 | ],
279 | });
280 | new CssMinimizerPlugin({
281 | test: /\.(css|sss)$/i,
282 | minimizerOptions: {
283 | processorOptions: {
284 | parser: "sugarss",
285 | },
286 | },
287 | }).apply(compiler);
288 |
289 | return compile(compiler).then((stats) => {
290 | expect(stats.compilation.errors).toEqual([]);
291 | expect(stats.compilation.warnings).toEqual([]);
292 |
293 | for (const file in stats.compilation.assets) {
294 | // eslint-disable-next-line no-continue
295 | if (/\.js$/.test(file)) continue;
296 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
297 | }
298 | });
299 | });
300 |
301 | it('matches snapshot for "stringifier" option with "Function" value', () => {
302 | const compiler = getCompiler({
303 | entry: {
304 | entry: `${__dirname}/fixtures/entry.js`,
305 | },
306 | });
307 | new CssMinimizerPlugin({
308 | parallel: false,
309 | minimizerOptions: {
310 | processorOptions: {
311 | stringifier: sugarss,
312 | },
313 | },
314 | }).apply(compiler);
315 |
316 | return compile(compiler).then((stats) => {
317 | expect(stats.compilation.errors).toEqual([]);
318 | expect(stats.compilation.warnings).toEqual([]);
319 |
320 | for (const file in stats.compilation.assets) {
321 | // eslint-disable-next-line no-continue
322 | if (/\.js$/.test(file)) continue;
323 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
324 | }
325 | });
326 | });
327 |
328 | it('matches snapshot for "stringifier" option with "String" value', () => {
329 | const compiler = getCompiler({
330 | entry: {
331 | entry: `${__dirname}/fixtures/entry.js`,
332 | },
333 | });
334 | new CssMinimizerPlugin({
335 | minimizerOptions: {
336 | processorOptions: {
337 | stringifier: "sugarss",
338 | },
339 | },
340 | }).apply(compiler);
341 |
342 | return compile(compiler).then((stats) => {
343 | expect(stats.compilation.errors).toEqual([]);
344 | expect(stats.compilation.warnings).toEqual([]);
345 |
346 | for (const file in stats.compilation.assets) {
347 | // eslint-disable-next-line no-continue
348 | if (/\.js$/.test(file)) continue;
349 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
350 | }
351 | });
352 | });
353 |
354 | it('matches snapshot for "syntax" option with "Function" value', () => {
355 | const compiler = getCompiler({
356 | entry: {
357 | entry: `${__dirname}/fixtures/sugarss.js`,
358 | },
359 | module: {},
360 | plugins: [
361 | new CopyPlugin({
362 | patterns: [
363 | {
364 | context: `${__dirname}/fixtures/sss`,
365 | from: `index.sss`,
366 | },
367 | ],
368 | }),
369 | new MiniCssExtractPlugin({
370 | filename: "[name].css",
371 | }),
372 | ],
373 | });
374 | new CssMinimizerPlugin({
375 | test: /\.(css|sss)$/i,
376 | parallel: false,
377 | minimizerOptions: {
378 | processorOptions: {
379 | syntax: sugarss,
380 | },
381 | },
382 | }).apply(compiler);
383 |
384 | return compile(compiler).then((stats) => {
385 | expect(stats.compilation.errors).toEqual([]);
386 | expect(stats.compilation.warnings).toEqual([]);
387 |
388 | for (const file in stats.compilation.assets) {
389 | // eslint-disable-next-line no-continue
390 | if (/\.js$/.test(file)) continue;
391 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
392 | }
393 | });
394 | });
395 |
396 | it('matches snapshot for "syntax" option with "String" value', () => {
397 | const compiler = getCompiler({
398 | entry: {
399 | entry: `${__dirname}/fixtures/sugarss.js`,
400 | },
401 | module: {},
402 | plugins: [
403 | new CopyPlugin({
404 | patterns: [
405 | {
406 | context: `${__dirname}/fixtures/sss`,
407 | from: `index.sss`,
408 | },
409 | ],
410 | }),
411 | new MiniCssExtractPlugin({
412 | filename: "[name].css",
413 | }),
414 | ],
415 | });
416 | new CssMinimizerPlugin({
417 | test: /\.(css|sss)$/i,
418 | minimizerOptions: {
419 | processorOptions: {
420 | syntax: "sugarss",
421 | },
422 | },
423 | }).apply(compiler);
424 |
425 | return compile(compiler).then((stats) => {
426 | expect(stats.compilation.errors).toEqual([]);
427 | expect(stats.compilation.warnings).toEqual([]);
428 |
429 | for (const file in stats.compilation.assets) {
430 | // eslint-disable-next-line no-continue
431 | if (/\.js$/.test(file)) continue;
432 | expect(readAsset(file, compiler, stats)).toMatchSnapshot(file);
433 | }
434 | });
435 | });
436 | });
437 |
--------------------------------------------------------------------------------
/test/parallel-option.test.js:
--------------------------------------------------------------------------------
1 | import os from "os";
2 |
3 | import { Worker } from "jest-worker";
4 |
5 | import CssMinimizerPlugin from "../src/index";
6 |
7 | import {
8 | compile,
9 | getCompiler,
10 | getErrors,
11 | getWarnings,
12 | readAssets,
13 | } from "./helpers";
14 |
15 | jest.mock("os", () => {
16 | const actualOs = jest.requireActual("os");
17 | const isAvailableParallelism =
18 | typeof actualOs.availableParallelism !== "undefined";
19 |
20 | const mocked = {
21 | availableParallelism: isAvailableParallelism ? jest.fn(() => 4) : undefined,
22 | cpus: jest.fn(() => {
23 | return { length: 4 };
24 | }),
25 | };
26 |
27 | return { ...actualOs, ...mocked };
28 | });
29 |
30 | // Based on https://github.com/facebook/jest/blob/edde20f75665c2b1e3c8937f758902b5cf28a7b4/packages/jest-runner/src/__tests__/test_runner.test.js
31 | let workerTransform;
32 | let workerEnd;
33 |
34 | const ENABLE_WORKER_THREADS =
35 | typeof process.env.ENABLE_WORKER_THREADS !== "undefined"
36 | ? process.env.ENABLE_WORKER_THREADS === "true"
37 | : true;
38 |
39 | jest.mock("jest-worker", () => {
40 | return {
41 | Worker: jest.fn().mockImplementation((workerPath) => {
42 | return {
43 | // eslint-disable-next-line global-require, import/no-dynamic-require
44 | transform: (workerTransform = jest.fn((data) =>
45 | // eslint-disable-next-line global-require, import/no-dynamic-require
46 | require(workerPath).transform(data),
47 | )),
48 | end: (workerEnd = jest.fn()),
49 | getStderr: jest.fn(),
50 | getStdout: jest.fn(),
51 | };
52 | }),
53 | };
54 | });
55 |
56 | const workerPath = require.resolve("../src/minify");
57 |
58 | const getParallelism = () => {
59 | if (typeof os.availableParallelism !== "undefined") {
60 | return os.availableParallelism();
61 | }
62 |
63 | return os.cpus().length;
64 | };
65 |
66 | describe("parallel option", () => {
67 | let compiler;
68 |
69 | beforeEach(() => {
70 | jest.clearAllMocks();
71 |
72 | compiler = getCompiler({
73 | entry: {
74 | one: `${__dirname}/fixtures/entry.js`,
75 | two: `${__dirname}/fixtures/entry.js`,
76 | three: `${__dirname}/fixtures/entry.js`,
77 | four: `${__dirname}/fixtures/entry.js`,
78 | },
79 | });
80 | });
81 |
82 | it("should match snapshot when a value is not specify", async () => {
83 | new CssMinimizerPlugin().apply(compiler);
84 |
85 | const stats = await compile(compiler);
86 |
87 | expect(Worker).toHaveBeenCalledTimes(1);
88 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
89 | enableWorkerThreads: ENABLE_WORKER_THREADS,
90 | numWorkers: getParallelism() - 1,
91 | });
92 | expect(workerTransform).toHaveBeenCalledTimes(
93 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
94 | );
95 | expect(workerEnd).toHaveBeenCalledTimes(1);
96 |
97 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
98 | expect(getErrors(stats)).toMatchSnapshot("errors");
99 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
100 | });
101 |
102 | it('should match snapshot for the "false" value', async () => {
103 | new CssMinimizerPlugin({ parallel: false }).apply(compiler);
104 |
105 | const stats = await compile(compiler);
106 |
107 | expect(Worker).toHaveBeenCalledTimes(0);
108 |
109 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
110 | expect(getErrors(stats)).toMatchSnapshot("errors");
111 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
112 | });
113 |
114 | it('should match snapshot for the "true" value', async () => {
115 | new CssMinimizerPlugin({ parallel: true }).apply(compiler);
116 |
117 | const stats = await compile(compiler);
118 |
119 | expect(Worker).toHaveBeenCalledTimes(1);
120 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
121 | enableWorkerThreads: ENABLE_WORKER_THREADS,
122 | numWorkers: Math.min(4, getParallelism() - 1),
123 | });
124 | expect(workerTransform).toHaveBeenCalledTimes(
125 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
126 | );
127 | expect(workerEnd).toHaveBeenCalledTimes(1);
128 |
129 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
130 | expect(getErrors(stats)).toMatchSnapshot("errors");
131 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
132 | });
133 |
134 | it('should match snapshot for the "undefined" value', async () => {
135 | new CssMinimizerPlugin({ parallel: undefined }).apply(compiler);
136 |
137 | const stats = await compile(compiler);
138 |
139 | expect(Worker).toHaveBeenCalledTimes(1);
140 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
141 | enableWorkerThreads: ENABLE_WORKER_THREADS,
142 | numWorkers: Math.min(4, getParallelism() - 1),
143 | });
144 | expect(workerTransform).toHaveBeenCalledTimes(
145 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
146 | );
147 | expect(workerEnd).toHaveBeenCalledTimes(1);
148 |
149 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
150 | expect(getErrors(stats)).toMatchSnapshot("errors");
151 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
152 | });
153 |
154 | it('should match snapshot for the "2" value', async () => {
155 | new CssMinimizerPlugin({ parallel: 2 }).apply(compiler);
156 |
157 | const stats = await compile(compiler);
158 |
159 | expect(Worker).toHaveBeenCalledTimes(1);
160 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
161 | enableWorkerThreads: ENABLE_WORKER_THREADS,
162 | numWorkers: 2,
163 | });
164 | expect(workerTransform).toHaveBeenCalledTimes(
165 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
166 | );
167 | expect(workerEnd).toHaveBeenCalledTimes(1);
168 |
169 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
170 | expect(getErrors(stats)).toMatchSnapshot("errors");
171 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
172 | });
173 |
174 | it('should match snapshot for the "true" value when only one file passed', async () => {
175 | compiler = getCompiler({
176 | entry: `${__dirname}/fixtures/entry.js`,
177 | });
178 |
179 | new CssMinimizerPlugin({ parallel: true }).apply(compiler);
180 |
181 | const stats = await compile(compiler);
182 |
183 | expect(Worker).toHaveBeenCalledTimes(1);
184 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
185 | enableWorkerThreads: ENABLE_WORKER_THREADS,
186 | numWorkers: Math.min(1, getParallelism() - 1),
187 | });
188 | expect(workerTransform).toHaveBeenCalledTimes(
189 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
190 | );
191 | expect(workerEnd).toHaveBeenCalledTimes(1);
192 |
193 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
194 | expect(getErrors(stats)).toMatchSnapshot("errors");
195 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
196 | });
197 |
198 | it('should match snapshot for the "true" value and the number of files is less than the number of cores', async () => {
199 | const entries = {};
200 |
201 | for (let i = 0; i < os.cpus().length / 2; i++) {
202 | entries[`entry-${i}`] = `${__dirname}/fixtures/entry.js`;
203 | }
204 |
205 | compiler = getCompiler({ entry: entries });
206 |
207 | new CssMinimizerPlugin({ parallel: true }).apply(compiler);
208 |
209 | const stats = await compile(compiler);
210 |
211 | expect(Worker).toHaveBeenCalledTimes(1);
212 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
213 | enableWorkerThreads: ENABLE_WORKER_THREADS,
214 | numWorkers: Math.min(Object.keys(entries).length, os.cpus().length - 1),
215 | });
216 | expect(workerTransform).toHaveBeenCalledTimes(
217 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
218 | );
219 | expect(workerEnd).toHaveBeenCalledTimes(1);
220 |
221 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
222 | expect(getErrors(stats)).toMatchSnapshot("errors");
223 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
224 | });
225 |
226 | it('should match snapshot for the "true" value and the number of files is same than the number of cores', async () => {
227 | const entries = {};
228 |
229 | for (let i = 0; i < os.cpus().length; i++) {
230 | entries[`entry-${i}`] = `${__dirname}/fixtures/entry.js`;
231 | }
232 |
233 | compiler = getCompiler({ entry: entries });
234 |
235 | new CssMinimizerPlugin({ parallel: true }).apply(compiler);
236 |
237 | const stats = await compile(compiler);
238 |
239 | expect(Worker).toHaveBeenCalledTimes(1);
240 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
241 | enableWorkerThreads: ENABLE_WORKER_THREADS,
242 | numWorkers: Math.min(Object.keys(entries).length, os.cpus().length - 1),
243 | });
244 | expect(workerTransform).toHaveBeenCalledTimes(
245 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
246 | );
247 | expect(workerEnd).toHaveBeenCalledTimes(1);
248 |
249 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
250 | expect(getErrors(stats)).toMatchSnapshot("errors");
251 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
252 | });
253 |
254 | it('should match snapshot for the "true" value and the number of files is more than the number of cores', async () => {
255 | const entries = {};
256 |
257 | for (let i = 0; i < os.cpus().length * 2; i++) {
258 | entries[`entry-${i}`] = `${__dirname}/fixtures/entry.js`;
259 | }
260 |
261 | compiler = getCompiler({
262 | entry: {
263 | one: `${__dirname}/fixtures/entry.js`,
264 | two: `${__dirname}/fixtures/entry.js`,
265 | three: `${__dirname}/fixtures/entry.js`,
266 | four: `${__dirname}/fixtures/entry.js`,
267 | five: `${__dirname}/fixtures/entry.js`,
268 | six: `${__dirname}/fixtures/entry.js`,
269 | seven: `${__dirname}/fixtures/entry.js`,
270 | eight: `${__dirname}/fixtures/entry.js`,
271 | },
272 | });
273 |
274 | new CssMinimizerPlugin({ parallel: true }).apply(compiler);
275 |
276 | const stats = await compile(compiler);
277 |
278 | expect(Worker).toHaveBeenCalledTimes(1);
279 | expect(Worker).toHaveBeenLastCalledWith(workerPath, {
280 | enableWorkerThreads: ENABLE_WORKER_THREADS,
281 | numWorkers: Math.min(Object.keys(entries).length, os.cpus().length - 1),
282 | });
283 | expect(workerTransform).toHaveBeenCalledTimes(
284 | Object.keys(readAssets(compiler, stats, /\.css$/)).length,
285 | );
286 | expect(workerEnd).toHaveBeenCalledTimes(1);
287 |
288 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
289 | expect(getErrors(stats)).toMatchSnapshot("errors");
290 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
291 | });
292 | });
293 |
--------------------------------------------------------------------------------
/test/sourceMap-option.test.js:
--------------------------------------------------------------------------------
1 | import webpack from "webpack";
2 | import MiniCssExtractPlugin from "mini-css-extract-plugin";
3 |
4 | import CssMinimizerPlugin from "../src/index";
5 |
6 | import {
7 | getCompiler,
8 | compile,
9 | readAssets,
10 | getErrors,
11 | getWarnings,
12 | } from "./helpers";
13 |
14 | expect.addSnapshotSerializer({
15 | test: (value) => {
16 | // For string that are valid JSON
17 | if (typeof value !== "string") {
18 | return false;
19 | }
20 |
21 | try {
22 | return typeof JSON.parse(value) === "object";
23 | } catch (e) {
24 | return false;
25 | }
26 | },
27 | print: (value) => JSON.stringify(JSON.parse(value), null, 4),
28 | });
29 |
30 | describe('when applied with "sourceMap" option', () => {
31 | const baseConfig = {
32 | devtool: "source-map",
33 | entry: {
34 | entry: `${__dirname}/fixtures/sourcemap/foo.scss`,
35 | entry2: `${__dirname}/fixtures/sourcemap/foo.css`,
36 | },
37 | module: {
38 | rules: [
39 | {
40 | test: /.s?css$/i,
41 | use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
42 | },
43 | ],
44 | },
45 | plugins: [
46 | new MiniCssExtractPlugin({
47 | filename: "[name].css",
48 | chunkFilename: "[id].[name].css",
49 | }),
50 | ],
51 | };
52 |
53 | it('should work with the "devtool" option', async () => {
54 | const compiler = getCompiler(baseConfig);
55 |
56 | new CssMinimizerPlugin().apply(compiler);
57 |
58 | const stats = await compile(compiler);
59 |
60 | expect(readAssets(compiler, stats, /\.css(\.map)?$/)).toMatchSnapshot(
61 | "assets",
62 | );
63 | expect(getErrors(stats)).toMatchSnapshot("errors");
64 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
65 | });
66 |
67 | it('should work with the "devtool" option and the "parallel" option with "false" value', async () => {
68 | const compiler = getCompiler(baseConfig);
69 |
70 | new CssMinimizerPlugin({
71 | parallel: false,
72 | }).apply(compiler);
73 |
74 | const stats = await compile(compiler);
75 |
76 | expect(readAssets(compiler, stats, /\.css(\.map)?$/)).toMatchSnapshot(
77 | "assets",
78 | );
79 | expect(getErrors(stats)).toMatchSnapshot("errors");
80 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
81 | });
82 |
83 | it('should work with the "devtool" option and the "parallel" option with "true" value', async () => {
84 | const compiler = getCompiler(baseConfig);
85 |
86 | new CssMinimizerPlugin({
87 | parallel: true,
88 | }).apply(compiler);
89 |
90 | const stats = await compile(compiler);
91 |
92 | expect(readAssets(compiler, stats, /\.css(\.map)?$/)).toMatchSnapshot(
93 | "assets",
94 | );
95 | expect(getErrors(stats)).toMatchSnapshot("errors");
96 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
97 | });
98 |
99 | it("should work with SourceMapDevToolPlugin plugin)", async () => {
100 | const config = Object.assign(baseConfig, {
101 | devtool: false,
102 | module: {
103 | rules: [
104 | {
105 | test: /.s?css$/i,
106 | use: [
107 | MiniCssExtractPlugin.loader,
108 | { loader: "css-loader", options: { sourceMap: true } },
109 | { loader: "sass-loader", options: { sourceMap: true } },
110 | ],
111 | },
112 | ],
113 | },
114 | plugins: [
115 | new MiniCssExtractPlugin({
116 | filename: "dist/[name].css",
117 | chunkFilename: "dist/[id].[name].css",
118 | }),
119 | new webpack.SourceMapDevToolPlugin({
120 | filename: "sourcemaps/[file].map",
121 | publicPath: "https://example.com/project/",
122 | fileContext: "dist",
123 | }),
124 | ],
125 | });
126 |
127 | const compiler = getCompiler(config);
128 |
129 | new CssMinimizerPlugin().apply(compiler);
130 |
131 | const stats = await compile(compiler);
132 |
133 | expect(readAssets(compiler, stats, /\.css(\.map)?$/)).toMatchSnapshot(
134 | "assets",
135 | );
136 | expect(getErrors(stats)).toMatchSnapshot("errors");
137 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
138 | });
139 |
140 | it("should work and emit warnings on broken sourcemaps", async () => {
141 | const emitBrokenSourceMapPlugin = new (class EmitBrokenSourceMapPlugin {
142 | apply(pluginCompiler) {
143 | pluginCompiler.hooks.compilation.tap(
144 | { name: this.constructor.name },
145 | (compilation) => {
146 | compilation.hooks.processAssets.tap(
147 | {
148 | name: this.constructor.name,
149 | stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
150 | },
151 | () => {
152 | compilation.additionalChunkAssets.push("broken-source-map.css");
153 |
154 | const assetContent = ".bar {color: red};";
155 |
156 | // eslint-disable-next-line no-param-reassign
157 | compilation.assets["broken-source-map.css"] = {
158 | size() {
159 | return assetContent.length;
160 | },
161 | source() {
162 | return assetContent;
163 | },
164 | sourceAndMap() {
165 | return {
166 | source: this.source(),
167 | map: {
168 | sources: [],
169 | names: [],
170 | mappings: "AAAA,KAAK,iBAAiB,KAAK,UAAU,OAAO",
171 | file: "x",
172 | sourcesContent: [],
173 | },
174 | };
175 | },
176 | };
177 | },
178 | );
179 | },
180 | );
181 | }
182 | })();
183 |
184 | const config = Object.assign(baseConfig, {
185 | devtool: "source-map",
186 | entry: {
187 | entry2: `${__dirname}/fixtures/sourcemap/foo.css`,
188 | },
189 | plugins: [
190 | emitBrokenSourceMapPlugin,
191 | new MiniCssExtractPlugin({
192 | filename: "dist/[name].css",
193 | chunkFilename: "dist/[id].[name].css",
194 | }),
195 | ],
196 | });
197 |
198 | const compiler = getCompiler(config);
199 |
200 | new CssMinimizerPlugin().apply(compiler);
201 |
202 | const stats = await compile(compiler);
203 |
204 | expect(readAssets(compiler, stats, /\.css(\.map)?$/)).toMatchSnapshot(
205 | "assets",
206 | );
207 | expect(getErrors(stats)).toMatchSnapshot("errors");
208 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
209 | expect(stats.compilation.warnings[0].toString()).toMatch(
210 | "contains invalid source map",
211 | );
212 | });
213 |
214 | it("should work and emit warning on valid sourcemap and minimizer error", async () => {
215 | const emitBrokenSourceMapPlugin = new (class EmitBrokenSourceMapPlugin {
216 | apply(pluginCompiler) {
217 | pluginCompiler.hooks.compilation.tap(
218 | { name: this.constructor.name },
219 | (compilation) => {
220 | compilation.hooks.processAssets.tap(
221 | {
222 | name: this.constructor.name,
223 | stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
224 | },
225 | () => {
226 | compilation.additionalChunkAssets.push("broken-source-map.css");
227 |
228 | const assetContent = ".bar {color: red};";
229 |
230 | // eslint-disable-next-line no-param-reassign
231 | compilation.assets["broken-source-map.css"] = {
232 | size() {
233 | return assetContent.length;
234 | },
235 | source() {
236 | return assetContent;
237 | },
238 | sourceAndMap() {
239 | return {
240 | source: this.source(),
241 | map: {
242 | version: 3,
243 | sources: ["test", "test2"],
244 | names: [],
245 | mappings: "AAAA,KAAK,iBAAiB,KAAK,UAAU,OAAO",
246 | file: "x",
247 | sourcesContent: [],
248 | },
249 | };
250 | },
251 | };
252 | },
253 | );
254 | },
255 | );
256 | }
257 | })();
258 |
259 | const config = Object.assign(baseConfig, {
260 | devtool: "source-map",
261 | entry: {
262 | entry2: `${__dirname}/fixtures/sourcemap/foo.css`,
263 | },
264 | plugins: [
265 | emitBrokenSourceMapPlugin,
266 | new MiniCssExtractPlugin({
267 | filename: "dist/[name].css",
268 | chunkFilename: "dist/[id].[name].css",
269 | }),
270 | ],
271 | });
272 |
273 | const compiler = getCompiler(config);
274 |
275 | new CssMinimizerPlugin({
276 | minify: (data) => {
277 | // eslint-disable-next-line global-require
278 | const postcss = require("postcss");
279 |
280 | const plugin = () => {
281 | let erroredDecl;
282 |
283 | return {
284 | postcssPlugin: "error-plugin",
285 | Declaration(decl) {
286 | erroredDecl = decl;
287 | },
288 | OnceExit() {
289 | throw erroredDecl.error("Postcss error");
290 | },
291 | };
292 | };
293 |
294 | plugin.postcss = true;
295 |
296 | const [[filename, input]] = Object.entries(data);
297 |
298 | return postcss([plugin])
299 | .process(input, { from: filename, to: filename })
300 | .then((result) => result);
301 | },
302 | }).apply(compiler);
303 |
304 | const stats = await compile(compiler);
305 |
306 | expect(getErrors(stats)).toMatchSnapshot("errors");
307 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
308 | });
309 |
310 | it("should work and do not contain sourcemap link in minified source", async () => {
311 | const compiler = getCompiler({
312 | devtool: false,
313 | entry: {
314 | foo: `${__dirname}/fixtures/foo.css`,
315 | },
316 | });
317 |
318 | new CssMinimizerPlugin().apply(compiler);
319 |
320 | const stats = await compile(compiler);
321 | const assets = readAssets(compiler, stats, /\.css$/);
322 | const [[, input]] = Object.entries(assets);
323 |
324 | expect(/sourceMappingURL/i.test(input)).toBe(false);
325 | });
326 | });
327 |
--------------------------------------------------------------------------------
/test/test-option.test.js:
--------------------------------------------------------------------------------
1 | import CssMinimizerPlugin from "../src/index";
2 |
3 | import {
4 | getCompiler,
5 | compile,
6 | readAssets,
7 | getErrors,
8 | getWarnings,
9 | } from "./helpers";
10 |
11 | describe('when applied with "test" option', () => {
12 | let compiler;
13 |
14 | beforeEach(() => {
15 | compiler = getCompiler({
16 | entry: {
17 | bar1: `${__dirname}/fixtures/test/bar1.css`,
18 | bar2: `${__dirname}/fixtures/test/bar2.css`,
19 | foo: `${__dirname}/fixtures/test/foo.css`,
20 | },
21 | });
22 | });
23 |
24 | it("matches snapshot with empty value", async () => {
25 | new CssMinimizerPlugin().apply(compiler);
26 |
27 | const stats = await compile(compiler);
28 |
29 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
30 | expect(getErrors(stats)).toMatchSnapshot("errors");
31 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
32 | });
33 |
34 | it('matches snapshot for a single "test" value (RegExp)', async () => {
35 | new CssMinimizerPlugin({
36 | test: /bar.*\.css$/,
37 | }).apply(compiler);
38 |
39 | const stats = await compile(compiler);
40 |
41 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
42 | expect(getErrors(stats)).toMatchSnapshot("errors");
43 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
44 | });
45 |
46 | it('matches snapshot for multiple "test" value (RegExp)', async () => {
47 | new CssMinimizerPlugin({
48 | test: [/bar1.*\.css$/, /bar2.*\.css$/],
49 | }).apply(compiler);
50 |
51 | const stats = await compile(compiler);
52 |
53 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
54 | expect(getErrors(stats)).toMatchSnapshot("errors");
55 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
56 | });
57 | });
58 |
--------------------------------------------------------------------------------
/test/validate-options.test.js:
--------------------------------------------------------------------------------
1 | import CssMinimizerPlugin from "../src";
2 |
3 | it("validation", () => {
4 | /* eslint-disable no-new */
5 | expect(() => {
6 | new CssMinimizerPlugin({ test: /foo/ });
7 | }).not.toThrow();
8 |
9 | expect(() => {
10 | new CssMinimizerPlugin({ test: "foo" });
11 | }).not.toThrow();
12 |
13 | expect(() => {
14 | new CssMinimizerPlugin({ test: [/foo/] });
15 | }).not.toThrow();
16 |
17 | expect(() => {
18 | new CssMinimizerPlugin({ test: [/foo/, /bar/] });
19 | }).not.toThrow();
20 |
21 | expect(() => {
22 | new CssMinimizerPlugin({ test: ["foo", "bar"] });
23 | }).not.toThrow();
24 |
25 | expect(() => {
26 | new CssMinimizerPlugin({ test: [/foo/, "bar"] });
27 | }).not.toThrow();
28 |
29 | expect(() => {
30 | new CssMinimizerPlugin({ test: true });
31 | }).toThrowErrorMatchingSnapshot();
32 |
33 | expect(() => {
34 | new CssMinimizerPlugin({ test: [true] });
35 | }).toThrowErrorMatchingSnapshot();
36 |
37 | expect(() => {
38 | new CssMinimizerPlugin({ include: /foo/ });
39 | }).not.toThrow();
40 |
41 | expect(() => {
42 | new CssMinimizerPlugin({ include: "foo" });
43 | }).not.toThrow();
44 |
45 | expect(() => {
46 | new CssMinimizerPlugin({ include: [/foo/] });
47 | }).not.toThrow();
48 |
49 | expect(() => {
50 | new CssMinimizerPlugin({ include: [/foo/, /bar/] });
51 | }).not.toThrow();
52 |
53 | expect(() => {
54 | new CssMinimizerPlugin({ include: ["foo", "bar"] });
55 | }).not.toThrow();
56 |
57 | expect(() => {
58 | new CssMinimizerPlugin({ include: [/foo/, "bar"] });
59 | }).not.toThrow();
60 |
61 | expect(() => {
62 | new CssMinimizerPlugin({ include: true });
63 | }).toThrowErrorMatchingSnapshot();
64 |
65 | expect(() => {
66 | new CssMinimizerPlugin({ include: [true] });
67 | }).toThrowErrorMatchingSnapshot();
68 |
69 | expect(() => {
70 | new CssMinimizerPlugin({ exclude: /foo/ });
71 | }).not.toThrow();
72 |
73 | expect(() => {
74 | new CssMinimizerPlugin({ exclude: "foo" });
75 | }).not.toThrow();
76 |
77 | expect(() => {
78 | new CssMinimizerPlugin({ exclude: [/foo/] });
79 | }).not.toThrow();
80 |
81 | expect(() => {
82 | new CssMinimizerPlugin({ exclude: [/foo/, /bar/] });
83 | }).not.toThrow();
84 |
85 | expect(() => {
86 | new CssMinimizerPlugin({ exclude: ["foo", "bar"] });
87 | }).not.toThrow();
88 |
89 | expect(() => {
90 | new CssMinimizerPlugin({ exclude: [/foo/, "bar"] });
91 | }).not.toThrow();
92 |
93 | expect(() => {
94 | new CssMinimizerPlugin({ exclude: true });
95 | }).toThrowErrorMatchingSnapshot();
96 |
97 | expect(() => {
98 | new CssMinimizerPlugin({ exclude: [true] });
99 | }).toThrowErrorMatchingSnapshot();
100 |
101 | expect(() => {
102 | new CssMinimizerPlugin({ minimizerOptions: {} });
103 | }).not.toThrow();
104 |
105 | expect(() => {
106 | new CssMinimizerPlugin({ minimizerOptions: [{}] });
107 | }).not.toThrow();
108 |
109 | expect(() => {
110 | new CssMinimizerPlugin({ minimizerOptions: null });
111 | }).toThrowErrorMatchingSnapshot();
112 |
113 | expect(() => {
114 | new CssMinimizerPlugin({
115 | minimizerOptions: { colormin: true },
116 | });
117 | }).not.toThrow();
118 |
119 | expect(() => {
120 | new CssMinimizerPlugin({ parallel: true });
121 | }).not.toThrow();
122 |
123 | expect(() => {
124 | new CssMinimizerPlugin({ parallel: false });
125 | }).not.toThrow();
126 |
127 | expect(() => {
128 | new CssMinimizerPlugin({ parallel: 2 });
129 | }).not.toThrow();
130 |
131 | expect(() => {
132 | new CssMinimizerPlugin({ parallel: "2" });
133 | }).toThrowErrorMatchingSnapshot();
134 |
135 | expect(() => {
136 | new CssMinimizerPlugin({ parallel: {} });
137 | }).toThrowErrorMatchingSnapshot();
138 |
139 | expect(() => {
140 | new CssMinimizerPlugin({ minify() {} });
141 | }).not.toThrow();
142 |
143 | expect(() => {
144 | new CssMinimizerPlugin({ minify: [() => {}] });
145 | }).not.toThrow();
146 |
147 | expect(() => {
148 | new CssMinimizerPlugin({ minify: true });
149 | }).toThrowErrorMatchingSnapshot();
150 |
151 | expect(() => {
152 | new CssMinimizerPlugin({ unknown: true });
153 | }).toThrowErrorMatchingSnapshot();
154 | /* eslint-enable no-new */
155 | });
156 |
--------------------------------------------------------------------------------
/test/warningsFilter-option.test.js:
--------------------------------------------------------------------------------
1 | import postcss from "postcss";
2 |
3 | import CssMinimizerPlugin from "../src/index";
4 |
5 | import {
6 | compile,
7 | getCompiler,
8 | getErrors,
9 | getWarnings,
10 | readAssets,
11 | } from "./helpers";
12 |
13 | describe("warningsFilter option", () => {
14 | it('should match snapshot for a "function" value', async () => {
15 | const plugin = () => {
16 | return {
17 | postcssPlugin: "warning-plugin",
18 | Once(root, { result }) {
19 | result.warn(`Warning from ${result.opts.from}`, {
20 | plugin: "warning-plugin",
21 | });
22 | },
23 | };
24 | };
25 |
26 | plugin.postcss = true;
27 |
28 | const compiler = getCompiler({
29 | entry: {
30 | foo: `${__dirname}/fixtures/test/foo.css`,
31 | bar1: `${__dirname}/fixtures/test/bar1.css`,
32 | bar2: `${__dirname}/fixtures/test/bar2.css`,
33 | },
34 | });
35 |
36 | new CssMinimizerPlugin({
37 | parallel: false,
38 | minify: (data) => {
39 | const [[fileName, input]] = Object.entries(data);
40 |
41 | return postcss([plugin])
42 | .process(input, { from: fileName, to: fileName })
43 | .then((result) => {
44 | return {
45 | code: result.css,
46 | map: result.map,
47 | error: result.error,
48 | warnings: result.warnings(),
49 | };
50 | });
51 | },
52 | warningsFilter(warning, file) {
53 | if (/foo/.test(file)) {
54 | return false;
55 | }
56 |
57 | return true;
58 | },
59 | }).apply(compiler);
60 |
61 | const stats = await compile(compiler);
62 |
63 | expect(readAssets(compiler, stats, /\.css$/)).toMatchSnapshot("assets");
64 | expect(getErrors(stats)).toMatchSnapshot("errors");
65 | expect(getWarnings(stats)).toMatchSnapshot("warnings");
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/test/worker.test.js:
--------------------------------------------------------------------------------
1 | import serialize from "serialize-javascript";
2 |
3 | import { transform } from "../src/minify";
4 |
5 | import CssMinimizerPlugin from "../src";
6 |
7 | import { normalizeErrors } from "./helpers";
8 |
9 | describe("worker", () => {
10 | it("should minify css", async () => {
11 | const options = {
12 | name: "entry.css",
13 | input: ".foo{color:red;}\n.bar{color:coral;}",
14 | inputSourceMap: {
15 | version: 3,
16 | sources: ["foo.css", "bar.css"],
17 | names: [],
18 | mappings: "AAAA,KAAK,iBAAiB,KAAK,UAAU,OAAO",
19 | file: "x",
20 | sourcesContent: [".foo{color:red;}", ".bar{color:coral;}"],
21 | },
22 | minimizer: {
23 | implementation: CssMinimizerPlugin.cssnanoMinify,
24 | options: { discardComments: false },
25 | },
26 | };
27 | const result = await transform(serialize(options));
28 |
29 | expect(result).toMatchSnapshot("result");
30 | });
31 |
32 | it("should work inputSourceMap as prev", async () => {
33 | const options = {
34 | name: "entry.css",
35 | input: ".foo{color:red;}\n.bar{color:coral;}",
36 | inputSourceMap: {
37 | version: 3,
38 | sources: ["foo.css", "bar.css"],
39 | names: [],
40 | mappings: "AAAA,KAAK,iBAAiB,KAAK,UAAU,OAAO",
41 | file: "x",
42 | sourcesContent: [".foo{color:red;}", ".bar{color:coral;}"],
43 | },
44 | minimizer: {
45 | implementation: CssMinimizerPlugin.cssnanoMinify,
46 | options: { discardComments: false },
47 | },
48 | };
49 | const result = await transform(serialize(options));
50 |
51 | expect(result).toMatchSnapshot("result");
52 | });
53 |
54 | it("should work options.minify function", async () => {
55 | const options = {
56 | name: "entry.css",
57 | input: ".foo{color:red;}\n.bar{color:coral;}",
58 | minimizer: {
59 | implementation: () => {
60 | return { code: ".minify {};" };
61 | },
62 | options: { discardComments: false },
63 | },
64 | };
65 | const result = await transform(serialize(options));
66 |
67 | expect(result).toMatchSnapshot("result");
68 | });
69 |
70 | it("should emit error", async () => {
71 | const options = {
72 | name: "entry.css",
73 | input: false,
74 | minimizer: {
75 | implementation: CssMinimizerPlugin.cssnanoMinify,
76 | options: { preset: "default" },
77 | },
78 | };
79 |
80 | try {
81 | await transform(serialize(options));
82 | } catch (error) {
83 | const normalizeError = { ...error };
84 |
85 | normalizeError.message = [error.message.split("\n")];
86 |
87 | expect(normalizeErrors(normalizeError.message)).toMatchSnapshot("error");
88 | }
89 | });
90 | });
91 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "moduleResolution": "node",
5 | "allowJs": true,
6 | "checkJs": true,
7 | "strict": true,
8 | "types": ["node"],
9 | "resolveJsonModule": true,
10 | "allowSyntheticDefaultImports": true
11 | },
12 | "include": ["./src/**/*"]
13 | }
14 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | export = CssMinimizerPlugin;
2 | /**
3 | * @template [T=CssNanoOptionsExtended]
4 | */
5 | declare class CssMinimizerPlugin {
6 | /**
7 | * @private
8 | * @param {any} input
9 | * @returns {boolean}
10 | */
11 | private static isSourceMap;
12 | /**
13 | * @private
14 | * @param {Warning | WarningObject | string} warning
15 | * @param {string} file
16 | * @param {WarningsFilter} [warningsFilter]
17 | * @param {TraceMap} [sourceMap]
18 | * @param {Compilation["requestShortener"]} [requestShortener]
19 | * @returns {Error & { hideStack?: boolean, file?: string } | undefined}
20 | */
21 | private static buildWarning;
22 | /**
23 | * @private
24 | * @param {Error | ErrorObject | string} error
25 | * @param {string} file
26 | * @param {TraceMap} [sourceMap]
27 | * @param {Compilation["requestShortener"]} [requestShortener]
28 | * @returns {Error}
29 | */
30 | private static buildError;
31 | /**
32 | * @private
33 | * @param {Parallel} parallel
34 | * @returns {number}
35 | */
36 | private static getAvailableNumberOfCores;
37 | /**
38 | * @private
39 | * @template T
40 | * @param {BasicMinimizerImplementation & MinimizeFunctionHelpers} implementation
41 | * @returns {boolean}
42 | */
43 | private static isSupportsWorkerThreads;
44 | /**
45 | * @param {BasePluginOptions & DefinedDefaultMinimizerAndOptions} [options]
46 | */
47 | constructor(
48 | options?:
49 | | (BasePluginOptions & DefinedDefaultMinimizerAndOptions)
50 | | undefined,
51 | );
52 | /**
53 | * @private
54 | * @type {InternalPluginOptions}
55 | */
56 | private options;
57 | /**
58 | * @private
59 | * @param {Compiler} compiler
60 | * @param {Compilation} compilation
61 | * @param {Record} assets
62 | * @param {{availableNumberOfCores: number}} optimizeOptions
63 | * @returns {Promise}
64 | */
65 | private optimize;
66 | /**
67 | * @param {Compiler} compiler
68 | * @returns {void}
69 | */
70 | apply(compiler: Compiler): void;
71 | }
72 | declare namespace CssMinimizerPlugin {
73 | export {
74 | cssnanoMinify,
75 | cssoMinify,
76 | cleanCssMinify,
77 | esbuildMinify,
78 | parcelCssMinify,
79 | lightningCssMinify,
80 | swcMinify,
81 | Schema,
82 | Compiler,
83 | Compilation,
84 | WebpackError,
85 | JestWorker,
86 | RawSourceMap,
87 | Asset,
88 | ProcessOptions,
89 | Syntax,
90 | Parser,
91 | Stringifier,
92 | TraceMap,
93 | CssNanoOptions,
94 | Warning,
95 | WarningObject,
96 | ErrorObject,
97 | MinimizedResult,
98 | Input,
99 | CustomOptions,
100 | InferDefaultType,
101 | MinimizerOptions,
102 | BasicMinimizerImplementation,
103 | MinimizeFunctionHelpers,
104 | MinimizerImplementation,
105 | InternalOptions,
106 | InternalResult,
107 | Parallel,
108 | Rule,
109 | Rules,
110 | WarningsFilter,
111 | BasePluginOptions,
112 | MinimizerWorker,
113 | ProcessOptionsExtender,
114 | CssNanoOptionsExtended,
115 | DefinedDefaultMinimizerAndOptions,
116 | InternalPluginOptions,
117 | };
118 | }
119 | import { cssnanoMinify } from "./utils";
120 | import { cssoMinify } from "./utils";
121 | import { cleanCssMinify } from "./utils";
122 | import { esbuildMinify } from "./utils";
123 | import { parcelCssMinify } from "./utils";
124 | import { lightningCssMinify } from "./utils";
125 | import { swcMinify } from "./utils";
126 | type Schema = import("schema-utils/declarations/validate").Schema;
127 | type Compiler = import("webpack").Compiler;
128 | type Compilation = import("webpack").Compilation;
129 | type WebpackError = import("webpack").WebpackError;
130 | type JestWorker = import("jest-worker").Worker;
131 | type RawSourceMap = import("@jridgewell/trace-mapping").EncodedSourceMap;
132 | type Asset = import("webpack").Asset;
133 | type ProcessOptions = import("postcss").ProcessOptions;
134 | type Syntax = import("postcss").Syntax;
135 | type Parser = import("postcss").Parser;
136 | type Stringifier = import("postcss").Stringifier;
137 | type TraceMap = import("@jridgewell/trace-mapping").TraceMap;
138 | type CssNanoOptions = {
139 | configFile?: string | undefined;
140 | preset?: [string, object] | string | undefined;
141 | };
142 | type Warning =
143 | | (Error & {
144 | plugin?: string;
145 | text?: string;
146 | source?: string;
147 | })
148 | | string;
149 | type WarningObject = {
150 | message: string;
151 | plugin?: string | undefined;
152 | text?: string | undefined;
153 | line?: number | undefined;
154 | column?: number | undefined;
155 | };
156 | type ErrorObject = {
157 | message: string;
158 | line?: number | undefined;
159 | column?: number | undefined;
160 | stack?: string | undefined;
161 | };
162 | type MinimizedResult = {
163 | code: string;
164 | map?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined;
165 | errors?: (string | Error | ErrorObject)[] | undefined;
166 | warnings?: (Warning | WarningObject)[] | undefined;
167 | };
168 | type Input = {
169 | [file: string]: string;
170 | };
171 | type CustomOptions = {
172 | [key: string]: any;
173 | };
174 | type InferDefaultType = T extends infer U ? U : CustomOptions;
175 | type MinimizerOptions = T extends any[]
176 | ? { [P in keyof T]?: InferDefaultType }
177 | : InferDefaultType;
178 | type BasicMinimizerImplementation = (
179 | input: Input,
180 | sourceMap: RawSourceMap | undefined,
181 | minifyOptions: InferDefaultType,
182 | ) => Promise | MinimizedResult;
183 | type MinimizeFunctionHelpers = {
184 | supportsWorkerThreads?: (() => boolean | undefined) | undefined;
185 | };
186 | type MinimizerImplementation = T extends any[]
187 | ? {
188 | [P in keyof T]: BasicMinimizerImplementation &
189 | MinimizeFunctionHelpers;
190 | }
191 | : BasicMinimizerImplementation & MinimizeFunctionHelpers;
192 | type InternalOptions = {
193 | name: string;
194 | input: string;
195 | inputSourceMap: RawSourceMap | undefined;
196 | minimizer: {
197 | implementation: MinimizerImplementation;
198 | options: MinimizerOptions;
199 | };
200 | };
201 | type InternalResult = {
202 | outputs: Array<{
203 | code: string;
204 | map: RawSourceMap | undefined;
205 | }>;
206 | warnings: Array;
207 | errors: Array;
208 | };
209 | type Parallel = undefined | boolean | number;
210 | type Rule = RegExp | string;
211 | type Rules = Rule[] | Rule;
212 | type WarningsFilter = (
213 | warning: Warning | WarningObject | string,
214 | file: string,
215 | source?: string,
216 | ) => boolean;
217 | type BasePluginOptions = {
218 | test?: Rule | undefined;
219 | include?: Rule | undefined;
220 | exclude?: Rule | undefined;
221 | warningsFilter?: WarningsFilter | undefined;
222 | parallel?: Parallel;
223 | };
224 | type MinimizerWorker = JestWorker & {
225 | transform: (options: string) => Promise;
226 | minify: (options: InternalOptions) => Promise;
227 | };
228 | type ProcessOptionsExtender =
229 | | ProcessOptions
230 | | {
231 | from?: string;
232 | to?: string;
233 | parser?: string | Syntax | Parser;
234 | stringifier?: string | Syntax | Stringifier;
235 | syntax?: string | Syntax;
236 | };
237 | type CssNanoOptionsExtended = CssNanoOptions & {
238 | processorOptions?: ProcessOptionsExtender;
239 | };
240 | type DefinedDefaultMinimizerAndOptions = T extends CssNanoOptionsExtended
241 | ? {
242 | minify?: MinimizerImplementation | undefined;
243 | minimizerOptions?: MinimizerOptions | undefined;
244 | }
245 | : {
246 | minify: MinimizerImplementation;
247 | minimizerOptions?: MinimizerOptions | undefined;
248 | };
249 | type InternalPluginOptions = BasePluginOptions & {
250 | minimizer: {
251 | implementation: MinimizerImplementation;
252 | options: MinimizerOptions;
253 | };
254 | };
255 |
--------------------------------------------------------------------------------
/types/minify.d.ts:
--------------------------------------------------------------------------------
1 | export type MinimizedResult = import("./index.js").MinimizedResult;
2 | export type InternalResult = import("./index.js").InternalResult;
3 | /** @typedef {import("./index.js").MinimizedResult} MinimizedResult */
4 | /** @typedef {import("./index.js").InternalResult} InternalResult */
5 | /**
6 | * @template T
7 | * @param {import("./index.js").InternalOptions} options
8 | * @returns {Promise}
9 | */
10 | export function minify(
11 | options: import("./index.js").InternalOptions,
12 | ): Promise;
13 | /**
14 | * @param {string} options
15 | * @returns {Promise}
16 | */
17 | export function transform(options: string): Promise;
18 |
--------------------------------------------------------------------------------
/types/utils.d.ts:
--------------------------------------------------------------------------------
1 | export type Task = () => Promise;
2 | export type Input = import("./index.js").Input;
3 | export type RawSourceMap = import("@jridgewell/trace-mapping").EncodedSourceMap;
4 | export type MinimizedResult = import("./index.js").MinimizedResult;
5 | export type CustomOptions = import("./index.js").CustomOptions;
6 | export type ProcessOptions = import("postcss").ProcessOptions;
7 | export type Postcss = import("postcss").Postcss;
8 | /**
9 | * @template T
10 | * @typedef {() => Promise} Task
11 | */
12 | /**
13 | * Run tasks with limited concurrency.
14 | * @template T
15 | * @param {number} limit - Limit of tasks that run at once.
16 | * @param {Task[]} tasks - List of tasks to run.
17 | * @returns {Promise} A promise that fulfills to an array of the results
18 | */
19 | export function throttleAll(limit: number, tasks: Task[]): Promise;
20 | /**
21 | * @template T
22 | * @param fn {(function(): any) | undefined}
23 | * @returns {function(): T}
24 | */
25 | export function memoize(fn: (() => any) | undefined): () => T;
26 | /**
27 | * @param {Input} input
28 | * @param {RawSourceMap} [sourceMap]
29 | * @param {CustomOptions} [minimizerOptions]
30 | * @return {Promise}
31 | */
32 | export function cssnanoMinify(
33 | input: Input,
34 | sourceMap?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined,
35 | minimizerOptions?: import("./index.js").CustomOptions | undefined,
36 | ): Promise;
37 | export namespace cssnanoMinify {
38 | function supportsWorkerThreads(): boolean;
39 | }
40 | /**
41 | * @param {Input} input
42 | * @param {RawSourceMap} [sourceMap]
43 | * @param {CustomOptions} [minimizerOptions]
44 | * @return {Promise}
45 | */
46 | export function cssoMinify(
47 | input: Input,
48 | sourceMap?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined,
49 | minimizerOptions?: import("./index.js").CustomOptions | undefined,
50 | ): Promise;
51 | export namespace cssoMinify {
52 | function supportsWorkerThreads(): boolean;
53 | }
54 | /**
55 | * @param {Input} input
56 | * @param {RawSourceMap} [sourceMap]
57 | * @param {CustomOptions} [minimizerOptions]
58 | * @return {Promise}
59 | */
60 | export function cleanCssMinify(
61 | input: Input,
62 | sourceMap?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined,
63 | minimizerOptions?: import("./index.js").CustomOptions | undefined,
64 | ): Promise;
65 | export namespace cleanCssMinify {
66 | function supportsWorkerThreads(): boolean;
67 | }
68 | /**
69 | * @param {Input} input
70 | * @param {RawSourceMap} [sourceMap]
71 | * @param {CustomOptions} [minimizerOptions]
72 | * @return {Promise}
73 | */
74 | export function esbuildMinify(
75 | input: Input,
76 | sourceMap?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined,
77 | minimizerOptions?: import("./index.js").CustomOptions | undefined,
78 | ): Promise;
79 | export namespace esbuildMinify {
80 | function supportsWorkerThreads(): boolean;
81 | }
82 | /**
83 | * @param {Input} input
84 | * @param {RawSourceMap} [sourceMap]
85 | * @param {CustomOptions} [minimizerOptions]
86 | * @return {Promise}
87 | */
88 | export function parcelCssMinify(
89 | input: Input,
90 | sourceMap?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined,
91 | minimizerOptions?: import("./index.js").CustomOptions | undefined,
92 | ): Promise;
93 | export namespace parcelCssMinify {
94 | function supportsWorkerThreads(): boolean;
95 | }
96 | /**
97 | * @param {Input} input
98 | * @param {RawSourceMap} [sourceMap]
99 | * @param {CustomOptions} [minimizerOptions]
100 | * @return {Promise}
101 | */
102 | export function lightningCssMinify(
103 | input: Input,
104 | sourceMap?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined,
105 | minimizerOptions?: import("./index.js").CustomOptions | undefined,
106 | ): Promise;
107 | export namespace lightningCssMinify {
108 | function supportsWorkerThreads(): boolean;
109 | }
110 | /**
111 | * @param {Input} input
112 | * @param {RawSourceMap} [sourceMap]
113 | * @param {CustomOptions} [minimizerOptions]
114 | * @return {Promise}
115 | */
116 | export function swcMinify(
117 | input: Input,
118 | sourceMap?: import("@jridgewell/trace-mapping").EncodedSourceMap | undefined,
119 | minimizerOptions?: import("./index.js").CustomOptions | undefined,
120 | ): Promise;
121 | export namespace swcMinify {
122 | function supportsWorkerThreads(): boolean;
123 | }
124 |
--------------------------------------------------------------------------------