Skip to content

Commit 9b96a97

Browse files
committed
the proof of concept about the new plugins API
1 parent 18df7ce commit 9b96a97

File tree

5 files changed

+130
-64
lines changed

5 files changed

+130
-64
lines changed

extractor.js

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
var postcss = require('postcss');
2+
var genericNames = require('generic-names');
3+
var path = require('path');
4+
5+
var Values = require('postcss-modules-values');
6+
var LocalByDefault = require('postcss-modules-local-by-default');
7+
var ExtractImports = require('postcss-modules-extract-imports');
8+
var Scope = require('postcss-modules-scope');
9+
var Parser = require('postcss-modules-parser');
10+
11+
/**
12+
* @param {array} options.append
13+
* @param {array} options.prepend
14+
* @param {array} options.use
15+
* @param {function} options.createImportedName
16+
* @param {function|string} options.generateScopedName
17+
* @param {string} options.mode
18+
* @param {string} options.rootDir
19+
* @param {function} fetch
20+
* @return {object}
21+
*/
22+
module.exports = function extractor(options, fetch) {
23+
options = options || {};
24+
var append = options.append;
25+
var prepend = options.prepend;
26+
var createImportedName = options.createImportedName;
27+
var generateScopedName = options.generateScopedName;
28+
var mode = options.mode;
29+
var use = options.use;
30+
var context = options.rootDir || process.cwd();
31+
32+
var scopedName;
33+
if (generateScopedName) {
34+
scopedName = typeof generateScopedName !== 'function'
35+
? genericNames(generateScopedName || '[name]__[local]___[hash:base64:5]', {context})
36+
: function (local, filename, css) {
37+
// had to wrap that function cause i didn't expected,
38+
// that generateShortName() and generateLongName() functions
39+
// use the fake path to file (relative to rootDir)
40+
// which result in the generated class names
41+
return generateScopedName(local, filename, css, context);
42+
};
43+
} else {
44+
// small fallback
45+
scopedName = function (local, filename) {
46+
return Scope.generateScopedName(local, path.relative(context, filename));
47+
}
48+
}
49+
50+
var plugins;
51+
if (use) {
52+
plugins = use;
53+
} else {
54+
plugins = (prepend || [])
55+
.concat([
56+
Values,
57+
mode
58+
? new LocalByDefault({mode})
59+
: LocalByDefault,
60+
createImportedName
61+
? new ExtractImports({createImportedName})
62+
: ExtractImports,
63+
new Scope({generateScopedName: scopedName}),
64+
], append || []);
65+
}
66+
67+
plugins = plugins.concat(new Parser({fetch}));
68+
69+
return postcss(plugins);
70+
}

index.js

+50-63
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ if (!global.Promise) { global.Promise = require('promise-polyfill') }
44
var fs = require('fs');
55
var path = require('path');
66
var through = require('through');
7-
var Core = require('css-modules-loader-core');
7+
var extractor = require('./extractor');
88
var FileSystemLoader = require('css-modules-loader-core/lib/file-system-loader');
99
var assign = require('object-assign');
1010
var stringHash = require('string-hash');
@@ -14,7 +14,8 @@ var ReadableStream = require('stream').Readable;
1414
Custom `generateScopedName` function for `postcss-modules-scope`.
1515
Short names consisting of source hash and line number.
1616
*/
17-
function generateShortName (name, filename, css) {
17+
function generateShortName (name, filename, css, context) {
18+
filename = path.relative(context, filename);
1819
// first occurrence of the name
1920
// TOOD: better match with regex
2021
var i = css.indexOf('.' + name);
@@ -28,7 +29,8 @@ function generateShortName (name, filename, css) {
2829
Custom `generateScopedName` function for `postcss-modules-scope`.
2930
Appends a hash of the css source.
3031
*/
31-
function generateLongName (name, filename) {
32+
function generateLongName (name, filename, css, context) {
33+
filename = path.relative(context, filename);
3234
var sanitisedPath = filename.replace(/\.[^\.\/\\]+$/, '')
3335
.replace(/[\W_]+/g, '_')
3436
.replace(/^_|_$/g, '');
@@ -93,59 +95,50 @@ var sourceByFile = {};
9395

9496
module.exports = function (browserify, options) {
9597
options = options || {};
96-
97-
// if no root directory is specified, assume the cwd
98-
var rootDir = options.rootDir || options.d;
99-
if (rootDir) { rootDir = path.resolve(rootDir); }
100-
if (!rootDir) { rootDir = process.cwd(); }
98+
options.rootDir = options.rootDir || options.d || undefined;
99+
options.append = options.postcssAfter || options.after || [];
100+
options.use = options.use || options.u || undefined;
101101

102102
var cssOutFilename = options.output || options.o;
103103
var jsonOutFilename = options.json || options.jsonOutput;
104104

105-
// PostCSS plugins passed to FileSystemLoader
106-
var plugins = options.use || options.u;
107-
if (!plugins) {
108-
plugins = getDefaultPlugins(options);
109-
}
110-
else {
111-
if (typeof plugins === 'string') {
112-
plugins = [plugins];
113-
}
114-
}
115-
116-
var postcssAfter = options.postcssAfter || options.after || [];
117-
plugins = plugins.concat(postcssAfter);
118-
119-
// load plugins by name (if a string is used)
120-
plugins = plugins.map(function requirePlugin (name) {
121-
// assume functions are already required plugins
122-
if (typeof name === 'function') {
123-
return name;
124-
}
125-
126-
var plugin = require(require.resolve(name));
127-
128-
// custom scoped name generation
129-
if (name === 'postcss-modules-scope') {
130-
options[name] = options[name] || {};
131-
if (!options[name].generateScopedName) {
132-
options[name].generateScopedName = generateLongName;
105+
// the compiled CSS stream needs to be avalible to the transform,
106+
// but re-created on each bundle call.
107+
var compiledCssStream;
108+
var instance = extractor(options, fetch);
109+
110+
function fetch(_to, from) {
111+
var to = _to.replace(/^["']|["']$/g, '');
112+
113+
return new Promise((resolve, reject) => {
114+
try {
115+
var filename = /\w/i.test(to[0])
116+
? require.resolve(to)
117+
: path.resolve(path.dirname(from), to);
118+
} catch (e) {
119+
return void reject(e);
133120
}
134-
}
135121

136-
if (name in options) {
137-
plugin = plugin(options[name]);
138-
}
139-
else {
140-
plugin = plugin.postcss || plugin();
141-
}
122+
fs.readFile(filename, 'utf8', (err, css) => {
123+
if (err) {
124+
return void reject(err);
125+
}
142126

143-
return plugin;
144-
});
127+
instance.process(css, {from: filename})
128+
.then(function (result) {
129+
var css = result.css;
130+
var tokens = result.root.tokens;
145131

146-
// the compiled CSS stream needs to be avalible to the transform,
147-
// but re-created on each bundle call.
148-
var compiledCssStream;
132+
assign(tokensByFile, tokens);
133+
sourceByFile[filename] = css;
134+
compiledCssStream.push(css);
135+
136+
resolve(tokens);
137+
})
138+
.catch(reject);
139+
});
140+
});
141+
}
149142

150143
function transform (filename) {
151144
// only handle .css files
@@ -156,25 +149,19 @@ module.exports = function (browserify, options) {
156149
// collect visited filenames
157150
filenames.push(filename);
158151

159-
var loader = new FileSystemLoader(rootDir, plugins);
160152
return through(function noop () {}, function end () {
161153
var self = this;
162154

163-
loader.fetch(path.relative(rootDir, filename), '/').then(function (tokens) {
164-
var output = 'module.exports = ' + JSON.stringify(tokens);
165-
166-
assign(tokensByFile, loader.tokensByFile);
167-
168-
// store this file's source to be written out to disk later
169-
sourceByFile[filename] = loader.finalSource;
155+
fetch(filename, filename)
156+
.then(function (tokens) {
157+
var output = 'module.exports = ' + JSON.stringify(tokens);
170158

171-
compiledCssStream.push(loader.finalSource);
172-
173-
self.queue(output);
174-
self.queue(null);
175-
}, function (err) {
176-
self.emit('error', err);
177-
});
159+
self.queue(output);
160+
self.queue(null);
161+
})
162+
.catch(function (err) {
163+
self.emit('error', err);
164+
});
178165
});
179166
}
180167

package.json

+7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
"main": "index.js",
66
"dependencies": {
77
"css-modules-loader-core": "^1.0.0",
8+
"generic-names": "^1.0.1",
89
"object-assign": "^3.0.0",
10+
"postcss": "^5.0.10",
11+
"postcss-modules-extract-imports": "^1.0.0",
12+
"postcss-modules-local-by-default": "^1.0.0",
13+
"postcss-modules-parser": "^1.0.1",
14+
"postcss-modules-scope": "^1.0.0",
15+
"postcss-modules-values": "^1.1.1",
916
"promise-polyfill": "^2.1.0",
1017
"string-hash": "^1.1.0",
1118
"through": "^2.3.7"
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
._cool_styles_styles__foo {
1+
._node_modules_cool_styles_styles__foo {
22
color: #F00;
33
}
4+
45
._styles__foo {
56
background: black;
67
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
._styles_2__bar {
22
background: #BAA;
33
}
4+
45
._styles_1__foo {
56
color: #F00;
67
}

0 commit comments

Comments
 (0)