Skip to content

Commit 8a129a7

Browse files
committed
Fixed caching issues
1 parent 611e819 commit 8a129a7

7 files changed

Lines changed: 136 additions & 135 deletions

File tree

README.md

Lines changed: 62 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -14,105 +14,79 @@
1414
</a>
1515
</p>
1616

17-
Serves as an alternative and also addition to `postcss-loader`. While webpack loaders are efficient, when you need to run some transformations on concatenated CSS (through `mini-css-extract-plugin` for example), loaders allows you to process just one file at time.
18-
19-
This plugin tries to solve this issue while taking great inspiration from [postcss-pipeline-webpack-plugin](https://github.com/mistakster/postcss-pipeline-webpack-plugin#readme). It allows you to **run PostCSS plugins** on generated (and newly emitted) **assets**, with support for webpack 5.x **filesystem cache** and ability to change content of **existing assets**, rather than a need to always generate new ones.
17+
Webpack loaders are pretty cool but limited to process and generate only one file at a time. If you are extracting critical CSS or media queries into separate files, you are no longer able to process these files. This plugin was made to solve this problem.
2018

2119
## Quick start
2220
```console
23-
npm i -D postcss postcss-webpack-plugin
21+
npx jsconfig.json
2422
```
2523

26-
```javascript
27-
const { PostCSSWebpackPlugin } = require('postcss-webpack-plugin');
28-
29-
new PostCSSWebpackPlugin({
30-
// Required: Array of PostCSS plugins that are passed directly to postcss function
31-
plugins: [require('cssnano')],
32-
/**
33-
* Optional: Can be either function, which receives asset file name as first
34-
* argument and should return new name ((filename: string) => string). Or a string
35-
* with a support for [base], [dir], [name], [ext] template tags. Defaults to the
36-
* existing filename (updates asset content) if not provided.
37-
*/
38-
filename?: string | ((filename: string) => string),
39-
/**
40-
* Optional: Custom function or RegExp to filter out unwanted assets. Defaults
41-
* to /\.css$/ to process only CSS files.
42-
*/
43-
filter?: RegExp | ((filename: string) => boolean),
44-
// Optional: Custom implementation of postcss, defaults to require('postcss')
45-
implementation?: require('postcss'),
46-
/**
47-
* Optional: Runs plugin also for newly emitted assets. Should be combined
48-
* with custom filter option in order to not get stuck processing the same
49-
* file all over again.
50-
*/
51-
additionalAssets?: true | undefined,
52-
})
53-
```
24+
By default the `jsconfig.json` is generated in **current working directory** (this is also where the script looks for existence of `webpack.config.js` or `package.json` file in order to try to extract path aliases).
25+
26+
This can be changed by providing path to custom working directory as a **first argument** of the cli (`npx jsconfig.json ~/Workspace/my-project`).
5427

55-
## Usage
56-
Sample usage in the webpack config object.
57-
58-
```javascript
59-
const { PostCSSWebpackPlugin } = require('postcss-webpack-plugin');
60-
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
61-
62-
module.exports = {
63-
entry: 'main.css',
64-
plugins: [
65-
new MiniCssExtractPlugin({
66-
filename: '[name].css',
67-
chunkFilename: '[id].[name].css',
68-
}),
69-
...(config?.plugins ?? []),
70-
],
71-
module: {
72-
rules: [
73-
{
74-
test: /.css$/i,
75-
use: [MiniCssExtractPlugin.loader, 'css-loader'],
76-
},
77-
],
78-
},
79-
plugins: [
80-
new PostCSSWebpackPlugin({
81-
plugins: [require('postcss-pxtorem'), require('cssnano')],
82-
})
83-
]
84-
};
28+
### Templates
29+
30+
There are few predefined jsconfig.json templates, that can be selected using `-t, --template` argument to help bootstrap the correct environment (`default` [default option], `nextjs`, `react`, `vuejs` and `node`).
31+
32+
```console
33+
npx jsconfig.json --template=nextjs
8534
```
8635

87-
### Advanced usage
88-
89-
Multiple instances can be chained together:
90-
91-
```javascript
92-
const { PostCSSWebpackPlugin } = require('postcss-webpack-plugin');
93-
94-
module.exports = {
95-
entry: 'main.css',
96-
// ...
97-
plugins: [
98-
new PostCSSWebpackPlugin({
99-
plugins: [require('postcss-pxtorem'), require('cssnano')],
100-
filename: '[name].rem[ext]',
101-
}),
102-
new PostCSSWebpackPlugin({
103-
plugins: [require('postcss-pxtorem'), require('cssnano')],
104-
filename: '[name].min[ext]',
105-
})
106-
]
107-
};
36+
### Additional CLI options
37+
38+
These allow you to further overwrite additional defaults or even provide custom `--baseUrl` and `--webpackConfigPath` that are used to generate correct paths to aliases. Lastly `--output` is used to define custom output directory for generated jsconfig.json file (this will not change the path aliases generation in any way). For more options run:
39+
40+
```console
41+
npx jsconfig.json --help
10842
```
10943

110-
This produces following output:
44+
```console
45+
Usage: npx jsconfig.json <srcPath> [options]
46+
47+
Options:
48+
--help Show help [boolean]
49+
--version Show version number [boolean]
50+
-o, --output Optional custom output directory for generated jsconfig.json
51+
file [string]
52+
-t, --template Base jsconfig.json template
53+
[choices: "default", "nextjs", "react", "vuejs", "node"] [default: "default"]
54+
-b, --baseUrl Custom base url used for paths generation [string]
55+
-c, --webpackConfig Custom path to webpack.config.js [string]
56+
-a, --target Specifies which default library (lib.d.ts) to use
57+
[string] [choices: "es3", "es5", "es6", "es2015", "es2016", "es2017", "es2018", "es2019",
58+
"es2020", "esnext"] [default: "es2020"]
59+
-m, --module Specifies the module system, when generating module code
60+
[string] [choices: "amd", "commonJS", "es2015", "es6", "esnext", "none", "system", "umd"]
61+
[default: "es2015"]
62+
-r, --moduleResolution Specifies how modules are resolved for imports
63+
[string] [choices: "node", "classic"] [default: "node"]
64+
-e, --experimentalDecorators Enables experimental support for proposed ES decorators
65+
[boolean]
66+
-s, --syntheticImports Allow default imports from modules with no default export.
67+
This does not affect code emit, just type checking. [boolean]
11168
```
11269

70+
### Support
71+
- Node.js >= **12.x**
72+
73+
74+
## Contributions
75+
76+
Contributions of any kind are very welcome!
77+
78+
This repository uses **conventional commits** in order to correctly generate CHANGELOG and release automatically. This means that all commits should follow correct form defined in the conventional commits specification. To make this process easier (and since there's pre-commit hook to validate commit messages. which won't let you commit invalid messages) you can run commit wizard using:
79+
11380
```
81+
npm run commit
82+
```
83+
84+
Which will take you through the process of generating correct format of the commit message.
85+
86+
### Development
87+
88+
To run cli in development you can use `npm run dev` to fires up nodemon which watches changes over the source files. By default the result is written to tmp/jsconfig.json when using nodemon (this looks int the root directory of the repository for webpack configs, you can provide custom webpack config while developing using CLI options `npm run dev -- --webpackConfig=/tmp/custom.webpack.test.config.js`).
89+
90+
### Tests
11491

115-
## Support
116-
- Node.js >= 14
117-
- postcss >= 8
118-
- webpack >= 5
92+
Tests are written using [jest framework](https://jestjs.io/). To run them use either `npm run test` or `npm run test:unit`, `npm run test e2e` to run each set of tests separately.

src/__tests__/helpers/testUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function getCompiler(config: webpack.Configuration = {}): webpack.Compiler {
99
entry: config.entry ?? './base.css',
1010
mode: 'development',
1111
devtool: config.devtool ?? false,
12-
context: path.resolve(__dirname, '../../__fixtures__'),
12+
context: path.resolve(__dirname, '../__mocks__'),
1313
output: {
1414
pathinfo: false,
1515
path: path.resolve(__dirname, '../../__outputs__'),

src/__tests__/index.test.ts

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,9 @@ describe('when used with additionalAssets option', () => {
5959
it('should apply postcss to additional assets', async () => {
6060
const compiler = getCompiler({
6161
plugins: [
62-
new PostCSSWebpackPlugin({
63-
plugins: [require('postcss-pxtorem')],
64-
filename: '[name].pxtorem[ext]',
65-
}),
6662
new PostCSSWebpackPlugin({
6763
plugins: [require('cssnano')],
68-
filename: '[name].minimized[ext]',
64+
filename: '[name].min[ext]',
6965
additionalAssets: true,
7066
}),
7167
],
@@ -76,19 +72,13 @@ describe('when used with additionalAssets option', () => {
7672
expect(readAssets(compiler, stats)).toMatchInlineSnapshot(`
7773
Object {
7874
"/main.css": "body {
79-
font-size: 0.9375rem;
80-
font-family: sans-serif;
81-
}
82-
83-
",
84-
"/main.pxtorem.css": "body {
85-
font-size: 0.9375rem;
75+
font-size: 15px;
8676
font-family: sans-serif;
8777
}
8878
8979
",
90-
"/main.pxtorem.minimized.css": "body{font-family:sans-serif;font-size:.9375rem}",
91-
"/main.pxtorem.minimized.minimized.css": "body{font-family:sans-serif;font-size:.9375rem}",
80+
"/main.min.css": "body{font-family:sans-serif;font-size:15px}",
81+
"/main.min.min.css": "body{font-family:sans-serif;font-size:15px}",
9282
}
9383
`);
9484
});
@@ -144,14 +134,15 @@ describe('when used with custom filter', () => {
144134
}
145135
`);
146136
});
137+
});
147138

148-
it('should apply changes only to filtered assets using regexp filter', async () => {
139+
describe('when used with custom filename option', () => {
140+
it('should interpolate template variables and emit new asset', async () => {
149141
const compiler = getCompiler({
150-
entry: { base: './base.css', component: './component.css' },
151142
plugins: [
152143
new PostCSSWebpackPlugin({
153144
plugins: [require('cssnano')],
154-
filter: filename => /component\.css$/.test(filename),
145+
filename: '[name].min[ext]',
155146
}),
156147
],
157148
});
@@ -160,25 +151,24 @@ describe('when used with custom filter', () => {
160151

161152
expect(readAssets(compiler, stats)).toMatchInlineSnapshot(`
162153
Object {
163-
"/base.css": "body {
154+
"/main.css": "body {
164155
font-size: 15px;
165156
font-family: sans-serif;
166157
}
167158
168159
",
169-
"/component.css": ".component{background:#000;font-size:12px}",
160+
"/main.min.css": "body{font-family:sans-serif;font-size:15px}",
170161
}
171162
`);
172163
});
173-
});
174164

175-
describe('when used with custom filename option', () => {
176-
it('should interpolate template variables and create new asset', async () => {
165+
it('should work with custom filename function option', async () => {
177166
const compiler = getCompiler({
178167
plugins: [
179168
new PostCSSWebpackPlugin({
180169
plugins: [require('cssnano')],
181-
filename: '[name].min[ext]',
170+
filename: filename =>
171+
`prefix__${filename.split('.')[0]}__postfix.css`,
182172
}),
183173
],
184174
});
@@ -193,18 +183,17 @@ describe('when used with custom filename option', () => {
193183
}
194184
195185
",
196-
"/main.min.css": "body{font-family:sans-serif;font-size:15px}",
186+
"/prefix__main__postfix.css": "body{font-family:sans-serif;font-size:15px}",
197187
}
198188
`);
199189
});
200190

201-
it('should work with custom filename function option', async () => {
191+
it('should work with custom paths', async () => {
202192
const compiler = getCompiler({
203193
plugins: [
204194
new PostCSSWebpackPlugin({
205195
plugins: [require('cssnano')],
206-
filename: filename =>
207-
`prefix__${filename.split('.')[0]}__postfix.css`,
196+
filename: './minimized/[base]',
208197
}),
209198
],
210199
});
@@ -219,17 +208,19 @@ describe('when used with custom filename option', () => {
219208
}
220209
221210
",
222-
"/prefix__main__postfix.css": "body{font-family:sans-serif;font-size:15px}",
211+
"/minimized/main.css": "body{font-family:sans-serif;font-size:15px}",
223212
}
224213
`);
225214
});
215+
});
226216

227-
it('should work with custom paths', async () => {
217+
describe('when used with source maps', () => {
218+
it('should work properly with source maps enabled', async () => {
228219
const compiler = getCompiler({
220+
devtool: 'source-map',
229221
plugins: [
230222
new PostCSSWebpackPlugin({
231-
plugins: [require('cssnano')],
232-
filename: './minimized/[base]',
223+
plugins: [require('postcss-pxtorem'), require('cssnano')],
233224
}),
234225
],
235226
});
@@ -238,25 +229,43 @@ describe('when used with custom filename option', () => {
238229

239230
expect(readAssets(compiler, stats)).toMatchInlineSnapshot(`
240231
Object {
241-
"/main.css": "body {
242-
font-size: 15px;
243-
font-family: sans-serif;
232+
"/main.css": "body{font-family:sans-serif;font-size:.9375rem}
233+
/*# sourceMappingURL=main.css.map*/",
244234
}
235+
`);
236+
});
245237

246-
",
247-
"/minimized/main.css": "body{font-family:sans-serif;font-size:15px}",
238+
it('should work properly with source maps disable', async () => {
239+
const compiler = getCompiler({
240+
devtool: false,
241+
plugins: [
242+
new PostCSSWebpackPlugin({
243+
plugins: [require('postcss-pxtorem'), require('cssnano')],
244+
}),
245+
],
246+
});
247+
248+
const stats = await compile(compiler);
249+
250+
expect(readAssets(compiler, stats)).toMatchInlineSnapshot(`
251+
Object {
252+
"/main.css": "body{font-family:sans-serif;font-size:.9375rem}",
248253
}
249254
`);
250255
});
251256
});
252257

253-
describe('when used with source maps enabled', () => {
254-
it('should work properly with external source maps', async () => {
258+
describe('when used with multiple instances', () => {
259+
it('should apply plugin postcss instances sequentially', async () => {
255260
const compiler = getCompiler({
256-
devtool: 'source-map',
257261
plugins: [
258262
new PostCSSWebpackPlugin({
259-
plugins: [require('postcss-pxtorem'), require('cssnano')],
263+
plugins: [require('postcss-pxtorem')],
264+
filename: '[name].rem[ext]',
265+
}),
266+
new PostCSSWebpackPlugin({
267+
plugins: [require('cssnano')],
268+
filename: '[name].min[ext]',
260269
}),
261270
],
262271
});
@@ -265,8 +274,20 @@ describe('when used with source maps enabled', () => {
265274

266275
expect(readAssets(compiler, stats)).toMatchInlineSnapshot(`
267276
Object {
268-
"/main.css": "body{font-family:sans-serif;font-size:.9375rem}
269-
/*# sourceMappingURL=main.css.map*/",
277+
"/main.css": "body {
278+
font-size: 15px;
279+
font-family: sans-serif;
280+
}
281+
282+
",
283+
"/main.min.css": "body{font-family:sans-serif;font-size:15px}",
284+
"/main.rem.css": "body {
285+
font-size: 0.9375rem;
286+
font-family: sans-serif;
287+
}
288+
289+
",
290+
"/main.rem.min.css": "body{font-family:sans-serif;font-size:.9375rem}",
270291
}
271292
`);
272293
});

0 commit comments

Comments
 (0)