@parcel/transformer-postcss 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -79,6 +79,16 @@ var _loadConfig = require("./loadConfig");
79
79
 
80
80
  var _constants = require("./constants");
81
81
 
82
+ function _diagnostic() {
83
+ const data = require("@parcel/diagnostic");
84
+
85
+ _diagnostic = function () {
86
+ return data;
87
+ };
88
+
89
+ return data;
90
+ }
91
+
82
92
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
83
93
 
84
94
  const COMPOSES_RE = /composes:.+from\s*("|').*("|')\s*;?/;
@@ -130,13 +140,16 @@ var _default = new (_plugin().Transformer)({
130
140
  asset,
131
141
  config,
132
142
  options,
133
- resolve
143
+ resolve,
144
+ logger
134
145
  }) {
135
146
  asset.type = 'css';
136
147
  let isLegacy = await isLegacyCssModule(asset);
137
148
 
138
149
  if (isLegacy && !config) {
139
150
  config = {
151
+ raw: {},
152
+ filePath: '',
140
153
  hydrated: {
141
154
  plugins: [],
142
155
  from: asset.filePath,
@@ -157,7 +170,72 @@ var _default = new (_plugin().Transformer)({
157
170
  let cssModules = null;
158
171
 
159
172
  if (config.hydrated.modules) {
160
- asset.meta.cssModulesCompiled = true; // TODO: should this be resolved from the project root?
173
+ asset.meta.cssModulesCompiled = true;
174
+ let code = asset.isASTDirty() ? null : await asset.getCode();
175
+
176
+ if (Object.keys(config.hydrated.modules).length === 0 && code && !isLegacy && !LEGACY_MODULE_RE.test(code)) {
177
+ let filename = _path().default.basename(config.filePath);
178
+
179
+ let message;
180
+ let configKey;
181
+ let hint;
182
+
183
+ if (config.raw.modules) {
184
+ message = (0, _diagnostic().md)`The "modules" option in __${filename}__ can be replaced with configuration for @parcel/transformer-css to improve build performance.`;
185
+ configKey = '/modules';
186
+ hint = (0, _diagnostic().md)`Remove the "modules" option from __${filename}__`;
187
+ } else {
188
+ message = (0, _diagnostic().md)`The "postcss-modules" plugin in __${filename}__ can be replaced with configuration for @parcel/transformer-css to improve build performance.`;
189
+ configKey = '/plugins/postcss-modules';
190
+ hint = (0, _diagnostic().md)`Remove the "postcss-modules" plugin from __${filename}__`;
191
+ }
192
+
193
+ let hints = ['Enable the "cssModules" option for "@parcel/transformer-css" in your package.json'];
194
+
195
+ if (plugins.length === 0) {
196
+ message += (0, _diagnostic().md)` Since there are no other plugins, __${filename}__ can be deleted safely.`;
197
+ hints.push((0, _diagnostic().md)`Delete __${filename}__`);
198
+ } else {
199
+ hints.push(hint);
200
+ }
201
+
202
+ let codeFrames;
203
+
204
+ if (_path().default.extname(filename) !== '.js') {
205
+ let contents = await asset.fs.readFile(config.filePath, 'utf8');
206
+ codeFrames = [{
207
+ language: 'json',
208
+ filePath: config.filePath,
209
+ code: contents,
210
+ codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
211
+ key: configKey,
212
+ type: 'key'
213
+ }])
214
+ }];
215
+ } else {
216
+ codeFrames = [{
217
+ filePath: config.filePath,
218
+ codeHighlights: [{
219
+ start: {
220
+ line: 1,
221
+ column: 1
222
+ },
223
+ end: {
224
+ line: 1,
225
+ column: 1
226
+ }
227
+ }]
228
+ }];
229
+ }
230
+
231
+ logger.warn({
232
+ message,
233
+ hints,
234
+ documentationURL: 'https://parceljs.org/languages/css/#enabling-css-modules-globally',
235
+ codeFrames
236
+ });
237
+ } // TODO: should this be resolved from the project root?
238
+
161
239
 
162
240
  let postcssModules = await options.packageManager.require('postcss-modules', asset.filePath, {
163
241
  range: '^4.3.0',
@@ -170,7 +248,6 @@ var _default = new (_plugin().Transformer)({
170
248
  generateScopedName: (name, filename) => `${name}_${(0, _hash().hashString)(_path().default.relative(options.projectRoot, filename)).substr(0, 6)}`,
171
249
  ...config.hydrated.modules
172
250
  }));
173
- let code = asset.isASTDirty() ? null : await asset.getCode();
174
251
 
175
252
  if (code == null || COMPOSES_RE.test(code)) {
176
253
  program.walkDecls(decl => {
package/lib/loadConfig.js CHANGED
@@ -25,6 +25,16 @@ function _utils() {
25
25
  return data;
26
26
  }
27
27
 
28
+ function _diagnostic() {
29
+ const data = require("@parcel/diagnostic");
30
+
31
+ _diagnostic = function () {
32
+ return data;
33
+ };
34
+
35
+ return data;
36
+ }
37
+
28
38
  function _nullthrows() {
29
39
  const data = _interopRequireDefault(require("nullthrows"));
30
40
 
@@ -51,7 +61,7 @@ var _loadPlugins = _interopRequireDefault(require("./loadPlugins"));
51
61
 
52
62
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
53
63
 
54
- async function configHydrator(configFile, config, resolveFrom, options) {
64
+ async function configHydrator(configFile, config, resolveFrom, options, logger) {
55
65
  if (configFile == null) {
56
66
  return;
57
67
  } // Load the custom config...
@@ -85,8 +95,62 @@ async function configHydrator(configFile, config, resolveFrom, options) {
85
95
  }
86
96
  }
87
97
 
98
+ let redundantPlugins = pluginArray.filter(p => p === 'autoprefixer' || p === 'postcss-preset-env');
99
+
100
+ if (redundantPlugins.length > 0) {
101
+ let filename = _path().default.basename(resolveFrom);
102
+
103
+ let message;
104
+ let hints = [];
105
+
106
+ if (redundantPlugins.length === pluginArray.length) {
107
+ message = (0, _diagnostic().md)`Parcel includes CSS transpilation and vendor prefixing by default. PostCSS config __${filename}__ contains only redundant plugins. Deleting it may significantly improve build performance.`;
108
+ hints.push((0, _diagnostic().md)`Delete __${filename}__`);
109
+ } else {
110
+ message = (0, _diagnostic().md)`Parcel includes CSS transpilation and vendor prefixing by default. PostCSS config __${filename}__ contains the following redundant plugins: ${[...redundantPlugins].map(p => _diagnostic().md.underline(p))}. Removing these may improve build performance.`;
111
+ hints.push((0, _diagnostic().md)`Remove the above plugins from __${filename}__`);
112
+ }
113
+
114
+ let codeFrames;
115
+
116
+ if (_path().default.extname(filename) !== '.js') {
117
+ let contents = await options.inputFS.readFile(resolveFrom, 'utf8');
118
+ codeFrames = [{
119
+ language: 'json',
120
+ filePath: resolveFrom,
121
+ code: contents,
122
+ codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, redundantPlugins.map(plugin => ({
123
+ key: `/plugins/${plugin}`,
124
+ type: 'key'
125
+ })))
126
+ }];
127
+ } else {
128
+ codeFrames = [{
129
+ filePath: resolveFrom,
130
+ codeHighlights: [{
131
+ start: {
132
+ line: 1,
133
+ column: 1
134
+ },
135
+ end: {
136
+ line: 1,
137
+ column: 1
138
+ }
139
+ }]
140
+ }];
141
+ }
142
+
143
+ logger.warn({
144
+ message,
145
+ hints,
146
+ documentationURL: 'https://parceljs.org/languages/css/#default-plugins',
147
+ codeFrames
148
+ });
149
+ }
150
+
88
151
  return {
89
152
  raw: configFile,
153
+ filePath: resolveFrom,
90
154
  hydrated: {
91
155
  plugins,
92
156
  from: config.searchPath,
@@ -142,5 +206,5 @@ async function load({
142
206
  }
143
207
  }
144
208
 
145
- return configHydrator(contents, config, configFile === null || configFile === void 0 ? void 0 : configFile.filePath, options);
209
+ return configHydrator(contents, config, configFile === null || configFile === void 0 ? void 0 : configFile.filePath, options, logger);
146
210
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcel/transformer-postcss",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -17,19 +17,21 @@
17
17
  "source": "src/PostCSSTransformer.js",
18
18
  "engines": {
19
19
  "node": ">= 12.0.0",
20
- "parcel": "^2.3.0"
20
+ "parcel": "^2.4.0"
21
21
  },
22
22
  "dependencies": {
23
- "@parcel/hash": "^2.3.0",
24
- "@parcel/plugin": "^2.3.0",
25
- "@parcel/utils": "^2.3.0",
23
+ "@parcel/diagnostic": "2.4.0",
24
+ "@parcel/hash": "2.4.0",
25
+ "@parcel/plugin": "2.4.0",
26
+ "@parcel/utils": "2.4.0",
26
27
  "clone": "^2.1.1",
27
28
  "nullthrows": "^1.1.1",
28
29
  "postcss-value-parser": "^4.2.0",
29
30
  "semver": "^5.7.1"
30
31
  },
31
32
  "devDependencies": {
32
- "postcss": "^8.4.5"
33
+ "postcss": "^8.4.5",
34
+ "postcss-modules": "^4.3.1"
33
35
  },
34
- "gitHead": "65ffb58e88024258c31e1f480241f293e29b25c5"
36
+ "gitHead": "b1bbfdab2e902d33c0b6ff75bfba2d22283a8de6"
35
37
  }
@@ -13,6 +13,7 @@ import typeof * as Postcss from 'postcss';
13
13
 
14
14
  import {load} from './loadConfig';
15
15
  import {POSTCSS_RANGE} from './constants';
16
+ import {md, generateJSONCodeHighlights} from '@parcel/diagnostic';
16
17
 
17
18
  const COMPOSES_RE = /composes:.+from\s*("|').*("|')\s*;?/;
18
19
  const FROM_IMPORT_RE = /.+from\s*(?:"|')(.*)(?:"|')\s*;?/;
@@ -49,11 +50,13 @@ export default (new Transformer({
49
50
  };
50
51
  },
51
52
 
52
- async transform({asset, config, options, resolve}) {
53
+ async transform({asset, config, options, resolve, logger}) {
53
54
  asset.type = 'css';
54
55
  let isLegacy = await isLegacyCssModule(asset);
55
56
  if (isLegacy && !config) {
56
57
  config = {
58
+ raw: {},
59
+ filePath: '',
57
60
  hydrated: {
58
61
  plugins: [],
59
62
  from: asset.filePath,
@@ -78,6 +81,76 @@ export default (new Transformer({
78
81
  if (config.hydrated.modules) {
79
82
  asset.meta.cssModulesCompiled = true;
80
83
 
84
+ let code = asset.isASTDirty() ? null : await asset.getCode();
85
+ if (
86
+ Object.keys(config.hydrated.modules).length === 0 &&
87
+ code &&
88
+ !isLegacy &&
89
+ !LEGACY_MODULE_RE.test(code)
90
+ ) {
91
+ let filename = path.basename(config.filePath);
92
+ let message;
93
+ let configKey;
94
+ let hint;
95
+ if (config.raw.modules) {
96
+ message = md`The "modules" option in __${filename}__ can be replaced with configuration for @parcel/transformer-css to improve build performance.`;
97
+ configKey = '/modules';
98
+ hint = md`Remove the "modules" option from __${filename}__`;
99
+ } else {
100
+ message = md`The "postcss-modules" plugin in __${filename}__ can be replaced with configuration for @parcel/transformer-css to improve build performance.`;
101
+ configKey = '/plugins/postcss-modules';
102
+ hint = md`Remove the "postcss-modules" plugin from __${filename}__`;
103
+ }
104
+
105
+ let hints = [
106
+ 'Enable the "cssModules" option for "@parcel/transformer-css" in your package.json',
107
+ ];
108
+ if (plugins.length === 0) {
109
+ message += md` Since there are no other plugins, __${filename}__ can be deleted safely.`;
110
+ hints.push(md`Delete __${filename}__`);
111
+ } else {
112
+ hints.push(hint);
113
+ }
114
+
115
+ let codeFrames;
116
+ if (path.extname(filename) !== '.js') {
117
+ let contents = await asset.fs.readFile(config.filePath, 'utf8');
118
+ codeFrames = [
119
+ {
120
+ language: 'json',
121
+ filePath: config.filePath,
122
+ code: contents,
123
+ codeHighlights: generateJSONCodeHighlights(contents, [
124
+ {
125
+ key: configKey,
126
+ type: 'key',
127
+ },
128
+ ]),
129
+ },
130
+ ];
131
+ } else {
132
+ codeFrames = [
133
+ {
134
+ filePath: config.filePath,
135
+ codeHighlights: [
136
+ {
137
+ start: {line: 1, column: 1},
138
+ end: {line: 1, column: 1},
139
+ },
140
+ ],
141
+ },
142
+ ];
143
+ }
144
+
145
+ logger.warn({
146
+ message,
147
+ hints,
148
+ documentationURL:
149
+ 'https://parceljs.org/languages/css/#enabling-css-modules-globally',
150
+ codeFrames,
151
+ });
152
+ }
153
+
81
154
  // TODO: should this be resolved from the project root?
82
155
  let postcssModules = await options.packageManager.require(
83
156
  'postcss-modules',
@@ -101,7 +174,6 @@ export default (new Transformer({
101
174
  }),
102
175
  );
103
176
 
104
- let code = asset.isASTDirty() ? null : await asset.getCode();
105
177
  if (code == null || COMPOSES_RE.test(code)) {
106
178
  program.walkDecls(decl => {
107
179
  let [, importPath] = FROM_IMPORT_RE.exec(decl.value) || [];
package/src/loadConfig.js CHANGED
@@ -7,6 +7,7 @@ import type {
7
7
  } from '@parcel/types';
8
8
  import path from 'path';
9
9
  import {relativePath} from '@parcel/utils';
10
+ import {md, generateJSONCodeHighlights} from '@parcel/diagnostic';
10
11
  import nullthrows from 'nullthrows';
11
12
  import clone from 'clone';
12
13
  import {POSTCSS_RANGE} from './constants';
@@ -15,6 +16,7 @@ import loadExternalPlugins from './loadPlugins';
15
16
 
16
17
  type ConfigResult = {|
17
18
  raw: any,
19
+ filePath: string,
18
20
  hydrated: {|
19
21
  plugins: Array<any>,
20
22
  from: FilePath,
@@ -26,8 +28,9 @@ type ConfigResult = {|
26
28
  async function configHydrator(
27
29
  configFile: any,
28
30
  config: Config,
29
- resolveFrom: ?FilePath,
31
+ resolveFrom: FilePath,
30
32
  options: PluginOptions,
33
+ logger: PluginLogger,
31
34
  ): Promise<?ConfigResult> {
32
35
  if (configFile == null) {
33
36
  return;
@@ -71,8 +74,67 @@ async function configHydrator(
71
74
  }
72
75
  }
73
76
 
77
+ let redundantPlugins = pluginArray.filter(
78
+ p => p === 'autoprefixer' || p === 'postcss-preset-env',
79
+ );
80
+ if (redundantPlugins.length > 0) {
81
+ let filename = path.basename(resolveFrom);
82
+ let message;
83
+ let hints = [];
84
+ if (redundantPlugins.length === pluginArray.length) {
85
+ message = md`Parcel includes CSS transpilation and vendor prefixing by default. PostCSS config __${filename}__ contains only redundant plugins. Deleting it may significantly improve build performance.`;
86
+ hints.push(md`Delete __${filename}__`);
87
+ } else {
88
+ message = md`Parcel includes CSS transpilation and vendor prefixing by default. PostCSS config __${filename}__ contains the following redundant plugins: ${[
89
+ ...redundantPlugins,
90
+ ].map(p =>
91
+ md.underline(p),
92
+ )}. Removing these may improve build performance.`;
93
+ hints.push(md`Remove the above plugins from __${filename}__`);
94
+ }
95
+
96
+ let codeFrames;
97
+ if (path.extname(filename) !== '.js') {
98
+ let contents = await options.inputFS.readFile(resolveFrom, 'utf8');
99
+ codeFrames = [
100
+ {
101
+ language: 'json',
102
+ filePath: resolveFrom,
103
+ code: contents,
104
+ codeHighlights: generateJSONCodeHighlights(
105
+ contents,
106
+ redundantPlugins.map(plugin => ({
107
+ key: `/plugins/${plugin}`,
108
+ type: 'key',
109
+ })),
110
+ ),
111
+ },
112
+ ];
113
+ } else {
114
+ codeFrames = [
115
+ {
116
+ filePath: resolveFrom,
117
+ codeHighlights: [
118
+ {
119
+ start: {line: 1, column: 1},
120
+ end: {line: 1, column: 1},
121
+ },
122
+ ],
123
+ },
124
+ ];
125
+ }
126
+
127
+ logger.warn({
128
+ message,
129
+ hints,
130
+ documentationURL: 'https://parceljs.org/languages/css/#default-plugins',
131
+ codeFrames,
132
+ });
133
+ }
134
+
74
135
  return {
75
136
  raw: configFile,
137
+ filePath: resolveFrom,
76
138
  hydrated: {
77
139
  plugins,
78
140
  from: config.searchPath,
@@ -143,5 +205,11 @@ export async function load({
143
205
  }
144
206
  }
145
207
 
146
- return configHydrator(contents, config, configFile?.filePath, options);
208
+ return configHydrator(
209
+ contents,
210
+ config,
211
+ configFile?.filePath,
212
+ options,
213
+ logger,
214
+ );
147
215
  }