1 | const localRequire = require('../utils/localRequire');
|
2 | const loadPlugins = require('../utils/loadPlugins');
|
3 | const md5 = require('../utils/md5');
|
4 | const postcss = require('postcss');
|
5 | const FileSystemLoader = require('css-modules-loader-core/lib/file-system-loader');
|
6 | const semver = require('semver');
|
7 | const path = require('path');
|
8 | const fs = require('@parcel/fs');
|
9 |
|
10 | module.exports = async function(asset) {
|
11 | let config = await getConfig(asset);
|
12 | if (!config) {
|
13 | return;
|
14 | }
|
15 |
|
16 | await asset.parseIfNeeded();
|
17 | let res = await postcss(config.plugins).process(asset.getCSSAst(), config);
|
18 |
|
19 | asset.ast.css = res.css;
|
20 | asset.ast.dirty = false;
|
21 | asset.sourceMap = res.map ? res.map.toJSON() : null;
|
22 | };
|
23 |
|
24 | async function getConfig(asset) {
|
25 | let config = await asset.getConfig(
|
26 | ['.postcssrc', '.postcssrc.json', '.postcssrc.js', 'postcss.config.js'],
|
27 | {packageKey: 'postcss'}
|
28 | );
|
29 |
|
30 | let enableModules =
|
31 | asset.options.rendition && asset.options.rendition.modules;
|
32 | if (!config && !asset.options.minify && !enableModules) {
|
33 | return;
|
34 | }
|
35 |
|
36 | config = config || {};
|
37 |
|
38 | if (asset.options.sourceMaps) {
|
39 | config.map = {inline: false, annotation: false, sourcesContent: true};
|
40 | }
|
41 |
|
42 | if (typeof config !== 'object') {
|
43 | throw new Error('PostCSS config should be an object.');
|
44 | }
|
45 |
|
46 | let postcssModulesConfig = {
|
47 | getJSON: (filename, json) => (asset.cssModules = json),
|
48 | Loader: createLoader(asset),
|
49 | generateScopedName: (name, filename) =>
|
50 | `_${name}_${md5(filename).substr(0, 5)}`
|
51 | };
|
52 |
|
53 | if (config.plugins && config.plugins['postcss-modules']) {
|
54 | postcssModulesConfig = Object.assign(
|
55 | config.plugins['postcss-modules'],
|
56 | postcssModulesConfig
|
57 | );
|
58 | delete config.plugins['postcss-modules'];
|
59 | }
|
60 |
|
61 | config.plugins = await loadPlugins(config.plugins, asset.name);
|
62 |
|
63 | if (config.modules || enableModules) {
|
64 | let postcssModules = await localRequire('postcss-modules', asset.name);
|
65 | config.plugins.push(postcssModules(postcssModulesConfig));
|
66 | }
|
67 |
|
68 | if (asset.options.minify) {
|
69 | let cssnano = await localRequire('cssnano', asset.name);
|
70 | let {version} = await localRequire('cssnano/package.json', asset.name);
|
71 | config.plugins.push(
|
72 | cssnano(
|
73 | (await asset.getConfig(['cssnano.config.js'])) || {
|
74 |
|
75 |
|
76 |
|
77 | safe: semver.satisfies(version, '<4.0.0-rc')
|
78 | }
|
79 | )
|
80 | );
|
81 | }
|
82 |
|
83 | config.from = asset.name;
|
84 | config.to = asset.name;
|
85 | return config;
|
86 | }
|
87 |
|
88 | const createLoader = asset =>
|
89 | class ParcelFileSystemLoader extends FileSystemLoader {
|
90 | async fetch(composesPath, relativeTo) {
|
91 | let importPath = composesPath.replace(/^["']|["']$/g, '');
|
92 | const {resolved} = asset.resolveDependency(importPath, relativeTo);
|
93 | let rootRelativePath = path.resolve(path.dirname(relativeTo), resolved);
|
94 | const root = path.resolve('/');
|
95 |
|
96 |
|
97 | if (rootRelativePath.startsWith(root)) {
|
98 | rootRelativePath = rootRelativePath.substr(root.length);
|
99 | }
|
100 |
|
101 | const source = await fs.readFile(resolved, 'utf-8');
|
102 | const {exportTokens} = await this.core.load(
|
103 | source,
|
104 | rootRelativePath,
|
105 | undefined,
|
106 | this.fetch.bind(this)
|
107 | );
|
108 | return exportTokens;
|
109 | }
|
110 |
|
111 | get finalSource() {
|
112 | return '';
|
113 | }
|
114 | };
|