@parcel/transformer-postcss 2.0.0-nightly.143 → 2.0.0-nightly.1430
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.
- package/lib/PostCSSTransformer.js +266 -160
- package/lib/constants.js +8 -0
- package/lib/loadConfig.js +162 -0
- package/lib/loadPlugins.js +6 -9
- package/package.json +19 -10
- package/src/PostCSSTransformer.js +237 -136
- package/src/constants.js +3 -0
- package/src/loadConfig.js +215 -0
- package/src/loadPlugins.js +20 -3
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {
|
|
3
|
+
Config,
|
|
4
|
+
FilePath,
|
|
5
|
+
PluginOptions,
|
|
6
|
+
PluginLogger,
|
|
7
|
+
} from '@parcel/types';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import {md, generateJSONCodeHighlights} from '@parcel/diagnostic';
|
|
10
|
+
import nullthrows from 'nullthrows';
|
|
11
|
+
import clone from 'clone';
|
|
12
|
+
import {POSTCSS_RANGE} from './constants';
|
|
13
|
+
|
|
14
|
+
import loadExternalPlugins from './loadPlugins';
|
|
15
|
+
|
|
16
|
+
type ConfigResult = {|
|
|
17
|
+
raw: any,
|
|
18
|
+
filePath: string,
|
|
19
|
+
hydrated: {|
|
|
20
|
+
plugins: Array<any>,
|
|
21
|
+
from: FilePath,
|
|
22
|
+
to: FilePath,
|
|
23
|
+
modules: any,
|
|
24
|
+
|},
|
|
25
|
+
|};
|
|
26
|
+
|
|
27
|
+
async function configHydrator(
|
|
28
|
+
configFile: any,
|
|
29
|
+
config: Config,
|
|
30
|
+
resolveFrom: FilePath,
|
|
31
|
+
options: PluginOptions,
|
|
32
|
+
logger: PluginLogger,
|
|
33
|
+
): Promise<?ConfigResult> {
|
|
34
|
+
if (configFile == null) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Load the custom config...
|
|
39
|
+
let modulesConfig;
|
|
40
|
+
let configFilePlugins = clone(configFile.plugins);
|
|
41
|
+
if (
|
|
42
|
+
configFilePlugins != null &&
|
|
43
|
+
typeof configFilePlugins === 'object' &&
|
|
44
|
+
configFilePlugins['postcss-modules'] != null
|
|
45
|
+
) {
|
|
46
|
+
modulesConfig = configFilePlugins['postcss-modules'];
|
|
47
|
+
delete configFilePlugins['postcss-modules'];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!modulesConfig && configFile.modules) {
|
|
51
|
+
modulesConfig = {};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let plugins = await loadExternalPlugins(
|
|
55
|
+
configFilePlugins,
|
|
56
|
+
nullthrows(resolveFrom),
|
|
57
|
+
options,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// contents is either:
|
|
61
|
+
// from JSON: { plugins: { 'postcss-foo': { ...opts } } }
|
|
62
|
+
// from JS (v8): { plugins: [ { postcssPlugin: 'postcss-foo', ...visitor callback functions } ]
|
|
63
|
+
// from JS (v7): { plugins: [ [Function: ...] ]
|
|
64
|
+
let pluginArray = Array.isArray(configFilePlugins)
|
|
65
|
+
? configFilePlugins
|
|
66
|
+
: Object.keys(configFilePlugins);
|
|
67
|
+
for (let p of pluginArray) {
|
|
68
|
+
if (typeof p === 'string') {
|
|
69
|
+
config.addDevDependency({
|
|
70
|
+
specifier: p,
|
|
71
|
+
resolveFrom: nullthrows(resolveFrom),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let redundantPlugins = pluginArray.filter(
|
|
77
|
+
p => p === 'autoprefixer' || p === 'postcss-preset-env',
|
|
78
|
+
);
|
|
79
|
+
if (redundantPlugins.length > 0) {
|
|
80
|
+
let filename = path.basename(resolveFrom);
|
|
81
|
+
let isPackageJson = filename === 'package.json';
|
|
82
|
+
let message;
|
|
83
|
+
let hints = [];
|
|
84
|
+
if (!isPackageJson && 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
|
+
let prefix = isPackageJson ? '/postcss' : '';
|
|
100
|
+
codeFrames = [
|
|
101
|
+
{
|
|
102
|
+
language: 'json',
|
|
103
|
+
filePath: resolveFrom,
|
|
104
|
+
code: contents,
|
|
105
|
+
codeHighlights: generateJSONCodeHighlights(
|
|
106
|
+
contents,
|
|
107
|
+
redundantPlugins.map(plugin => ({
|
|
108
|
+
key: `${prefix}/plugins/${plugin}`,
|
|
109
|
+
type: 'key',
|
|
110
|
+
})),
|
|
111
|
+
),
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
} else {
|
|
115
|
+
codeFrames = [
|
|
116
|
+
{
|
|
117
|
+
filePath: resolveFrom,
|
|
118
|
+
codeHighlights: [
|
|
119
|
+
{
|
|
120
|
+
start: {line: 1, column: 1},
|
|
121
|
+
end: {line: 1, column: 1},
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
logger.warn({
|
|
129
|
+
message,
|
|
130
|
+
hints,
|
|
131
|
+
documentationURL: 'https://parceljs.org/languages/css/#default-plugins',
|
|
132
|
+
codeFrames,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
raw: configFile,
|
|
138
|
+
filePath: resolveFrom,
|
|
139
|
+
hydrated: {
|
|
140
|
+
plugins,
|
|
141
|
+
from: config.searchPath,
|
|
142
|
+
to: config.searchPath,
|
|
143
|
+
modules: modulesConfig,
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function load({
|
|
149
|
+
config,
|
|
150
|
+
options,
|
|
151
|
+
logger,
|
|
152
|
+
}: {|
|
|
153
|
+
config: Config,
|
|
154
|
+
options: PluginOptions,
|
|
155
|
+
logger: PluginLogger,
|
|
156
|
+
|}): Promise<?ConfigResult> {
|
|
157
|
+
if (!config.isSource) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let configFile: any = await config.getConfig(
|
|
162
|
+
[
|
|
163
|
+
'.postcssrc',
|
|
164
|
+
'.postcssrc.json',
|
|
165
|
+
'.postcssrc.js',
|
|
166
|
+
'.postcssrc.cjs',
|
|
167
|
+
'.postcssrc.mjs',
|
|
168
|
+
'postcss.config.js',
|
|
169
|
+
'postcss.config.cjs',
|
|
170
|
+
'postcss.config.mjs',
|
|
171
|
+
],
|
|
172
|
+
{packageKey: 'postcss'},
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
let contents = null;
|
|
176
|
+
if (configFile) {
|
|
177
|
+
config.addDevDependency({
|
|
178
|
+
specifier: 'postcss',
|
|
179
|
+
resolveFrom: config.searchPath,
|
|
180
|
+
range: POSTCSS_RANGE,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
contents = configFile.contents;
|
|
184
|
+
let isDynamic =
|
|
185
|
+
configFile && path.extname(configFile.filePath).endsWith('js');
|
|
186
|
+
if (isDynamic) {
|
|
187
|
+
// We have to invalidate on startup in case the config is non-deterministic,
|
|
188
|
+
// e.g. using unknown environment variables, reading from the filesystem, etc.
|
|
189
|
+
logger.warn({
|
|
190
|
+
message:
|
|
191
|
+
'WARNING: Using a JavaScript PostCSS config file means losing out on caching features of Parcel. Use a .postcssrc(.json) file whenever possible.',
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (typeof contents !== 'object') {
|
|
196
|
+
throw new Error('PostCSS config should be an object.');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (
|
|
200
|
+
contents.plugins == null ||
|
|
201
|
+
typeof contents.plugins !== 'object' ||
|
|
202
|
+
Object.keys(contents.plugins).length === 0
|
|
203
|
+
) {
|
|
204
|
+
throw new Error('PostCSS config must have plugins');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return configHydrator(
|
|
209
|
+
contents,
|
|
210
|
+
config,
|
|
211
|
+
configFile?.filePath,
|
|
212
|
+
options,
|
|
213
|
+
logger,
|
|
214
|
+
);
|
|
215
|
+
}
|
package/src/loadPlugins.js
CHANGED
|
@@ -11,14 +11,28 @@ export default async function loadExternalPlugins(
|
|
|
11
11
|
if (Array.isArray(plugins)) {
|
|
12
12
|
return Promise.all(
|
|
13
13
|
plugins
|
|
14
|
-
.map(p =>
|
|
14
|
+
.map(p =>
|
|
15
|
+
loadPlugin(
|
|
16
|
+
p,
|
|
17
|
+
relative,
|
|
18
|
+
null,
|
|
19
|
+
options.packageManager,
|
|
20
|
+
options.shouldAutoInstall,
|
|
21
|
+
),
|
|
22
|
+
)
|
|
15
23
|
.filter(Boolean),
|
|
16
24
|
);
|
|
17
25
|
} else if (typeof plugins === 'object') {
|
|
18
26
|
let _plugins = plugins;
|
|
19
27
|
let mapPlugins = await Promise.all(
|
|
20
28
|
Object.keys(plugins).map(p =>
|
|
21
|
-
loadPlugin(
|
|
29
|
+
loadPlugin(
|
|
30
|
+
p,
|
|
31
|
+
relative,
|
|
32
|
+
_plugins[p],
|
|
33
|
+
options.packageManager,
|
|
34
|
+
options.shouldAutoInstall,
|
|
35
|
+
),
|
|
22
36
|
),
|
|
23
37
|
);
|
|
24
38
|
return mapPlugins.filter(Boolean);
|
|
@@ -32,12 +46,15 @@ async function loadPlugin(
|
|
|
32
46
|
relative: FilePath,
|
|
33
47
|
options: mixed = {},
|
|
34
48
|
packageManager: PackageManager,
|
|
49
|
+
shouldAutoInstall: boolean,
|
|
35
50
|
): mixed {
|
|
36
51
|
if (typeof pluginArg !== 'string') {
|
|
37
52
|
return pluginArg;
|
|
38
53
|
}
|
|
39
54
|
|
|
40
|
-
let plugin = await packageManager.require(pluginArg, relative
|
|
55
|
+
let plugin = await packageManager.require(pluginArg, relative, {
|
|
56
|
+
shouldAutoInstall,
|
|
57
|
+
});
|
|
41
58
|
plugin = plugin.default || plugin;
|
|
42
59
|
|
|
43
60
|
if (
|