Skip to content

Commit ab1d29a

Browse files
committed
Merge pull request #18 from css-modules/api.updates
Api.updates
2 parents cea7db0 + 8a053e3 commit ab1d29a

File tree

4 files changed

+131
-35
lines changed

4 files changed

+131
-35
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
"mocha": true
66
},
77
"rules": {
8+
"no-use-before-define": [2, "nofunc"]
89
}
910
}

README.md

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,55 @@ $ npm i css-modules-require-hook
2626
require('css-modules-require-hook');
2727
```
2828

29-
## Specifying options
29+
## Available options
30+
31+
Providing additional options allows you to get advanced experience. See the variants below.
32+
33+
```javascript
34+
var hook = require('css-modules-require-hook');
35+
hook({ /* options */ });
36+
```
37+
38+
### `rootDir` option
39+
40+
Aliases are `root`, `d`.
41+
42+
Absolute path to your project's root directory. This is optional but providing it will result in better generated classnames. It can be obligatory, if you run require hook and build tools, like [css-modulesify](https://github.com/css-modules/css-modulesify) from different working directories.
43+
44+
### `use` option
45+
46+
Alias is `u`.
47+
48+
Custom list of plugins. This is optional but helps you to extend list of basic [postcss](https://github.com/postcss/postcss) plugins. Also helps to specify options for particular plugins.
49+
50+
### `createImportedName` option
51+
52+
Alias for the `createImportedName` option from the [postcss-modules-extract-imports](https://github.com/css-modules/postcss-modules-extract-imports) plugin. This is optional. Won't work if you `use` option.
53+
54+
### `generateScopedName` option
55+
56+
Custom function to generate class names. This is optional. Alias for the `generateScopedName` option from the [postcss-modules-scope](https://github.com/css-modules/postcss-modules-scope) plugin. Won't work if you `use` option.
57+
58+
### `mode` option
59+
60+
Alias for the `mode` option from the [postcss-modules-local-by-default](https://github.com/css-modules/postcss-modules-local-by-default) plugin. This is optional. Won't work if you `use` option.
61+
62+
## Examples
63+
64+
If you want to add custom functionality, for example [CSS Next](http://cssnext.io/setup/#as-a-postcss-plugin) plugin, you should provide the `use` option.
3065

3166
```javascript
32-
require('css-modules-require-hook')({
33-
// If you run css-modulesify and require-hook from different directories,
34-
// you have to specify similar root directories
35-
// in order to get the same class names
36-
root: '...', // please, use the absolute path here. It's process.cwd() by default
37-
// Setting this allows you to specify custom PostCSS plugins
38-
// You may use functions or strings, which match to the modules with the same name
39-
use: [] // may use `u` for short
67+
var hook = require('css-modules-require-hook');
68+
69+
hook({
70+
use: [
71+
// adding CSS Next plugin
72+
require('cssnext')(),
73+
74+
// adding basic css-modules plugins
75+
require('postcss-modules-extract-imports'),
76+
require('postcss-modules-local-by-default'),
77+
require('postcss-modules-scope')
78+
]
4079
});
4180
```

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"engines": {
77
"node": ">=0.12"
88
},
9+
"dependencies": {
10+
"lodash.isplainobject": "^3.2.0"
11+
},
912
"devDependencies": {
1013
"babel": "^5.8.20",
1114
"babel-eslint": "^4.0.5",

src/index.js

Lines changed: 79 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,84 @@ import hook from './hook';
33
import postcss from 'postcss';
44
import { dirname, join, parse, relative, resolve, sep } from 'path';
55
import { readFileSync } from 'fs';
6+
import isPlainObject from 'lodash.isplainobject';
67

78
import ExtractImports from 'postcss-modules-extract-imports';
89
import LocalByDefault from 'postcss-modules-local-by-default';
910
import Scope from 'postcss-modules-scope';
1011
import Parser from './parser';
1112

13+
let processCss;
14+
let rootDir;
15+
let plugins;
16+
17+
/**
18+
* @param {object} opts
19+
* @param {function} opts.generateScopedName
20+
* @param {function} opts.processCss|.p
21+
* @param {string} opts.rootDir|.root|.d
22+
* @param {array} opts.use|.u
23+
*/
24+
export default function buildOptions(opts = {}) {
25+
if (!isPlainObject(opts)) {
26+
throw new Error('Use plain object');
27+
}
28+
29+
processCss = get(opts, 'processCss|p');
30+
rootDir = get(opts, 'rootDir|root|d');
31+
rootDir = rootDir ? resolve(rootDir) : process.cwd();
32+
33+
const customPlugins = get(opts, 'use|u');
34+
if (Array.isArray(customPlugins)) {
35+
return void (plugins = customPlugins);
36+
}
37+
38+
plugins = [];
39+
40+
plugins.push(
41+
opts.mode
42+
? new LocalByDefault({mode: opts.mode})
43+
: LocalByDefault
44+
);
45+
46+
plugins.push(
47+
opts.createImportedName
48+
? new ExtractImports({createImportedName: opts.createImportedName})
49+
: ExtractImports
50+
);
51+
52+
plugins.push(
53+
opts.generateScopedName
54+
? new Scope({generateScopedName: opts.generateScopedName})
55+
: Scope
56+
);
57+
}
58+
1259
const escapedSeparator = sep.replace(/(.)/g, '\\$1');
1360
const relativePathPattern = new RegExp(`^.{1,2}$|^.{1,2}${escapedSeparator}`);
14-
15-
const defaultRoot = process.cwd();
1661
const tokensByFile = {};
17-
let plugins = [LocalByDefault, ExtractImports, Scope];
18-
let root = defaultRoot;
1962
let importNr = 0;
2063

64+
/**
65+
* @param {object} object
66+
* @param {string} keys 'a|b|c'
67+
* @return {*}
68+
*/
69+
function get(object, keys) {
70+
let key;
71+
72+
keys.split('|').some(k => {
73+
if (!object[k]) {
74+
return false;
75+
}
76+
77+
key = k;
78+
return true;
79+
});
80+
81+
return key ? object[key] : null;
82+
}
83+
2184
/**
2285
* @param {string} pathname
2386
* @return {boolean}
@@ -35,11 +98,10 @@ function isModule(pathname) {
3598
* @return {object}
3699
*/
37100
function load(sourceString, sourcePath, trace, pathFetcher) {
38-
const result = postcss(plugins.concat(new Parser({ pathFetcher, trace })))
39-
.process(sourceString, {from: sourcePath})
40-
.root;
101+
const lazyResult = postcss(plugins.concat(new Parser({ pathFetcher, trace })))
102+
.process(sourceString, {from: sourcePath});
41103

42-
return result.tokens;
104+
return { injectableSource: lazyResult.css, exportTokens: lazyResult.root.tokens };
43105
}
44106

45107
/**
@@ -54,7 +116,7 @@ function fetch(_newPath, _relativeTo, _trace) {
54116

55117
const relativeDir = dirname(_relativeTo);
56118
const rootRelativePath = resolve(relativeDir, newPath);
57-
let fileRelativePath = resolve(join(root, relativeDir), newPath);
119+
let fileRelativePath = resolve(join(rootDir, relativeDir), newPath);
58120

59121
if (isModule(newPath)) {
60122
fileRelativePath = require.resolve(newPath);
@@ -66,27 +128,18 @@ function fetch(_newPath, _relativeTo, _trace) {
66128
}
67129

68130
const source = readFileSync(fileRelativePath, 'utf-8');
69-
const exportTokens = load(source, rootRelativePath, trace, fetch);
131+
const { exportTokens, injectableSource } = load(source, rootRelativePath, trace, fetch);
70132

71133
tokensByFile[fileRelativePath] = exportTokens;
72134

135+
if (typeof processCss === 'function') {
136+
processCss(injectableSource);
137+
}
138+
73139
return exportTokens;
74140
}
75141

76-
hook(filename => fetch(`.${sep}${relative(root, filename)}`, '/'));
142+
// setting defaults
143+
buildOptions();
77144

78-
/**
79-
* @param {object} opts
80-
* @param {array} opts.u
81-
* @param {array} opts.use
82-
*/
83-
export default function configure(opts = {}) {
84-
const customPlugins = opts.u || opts.use;
85-
plugins = Array.isArray(customPlugins)
86-
? customPlugins
87-
: [LocalByDefault, ExtractImports, Scope];
88-
89-
root = opts.root && typeof opts.root === 'string'
90-
? opts.root
91-
: defaultRoot;
92-
}
145+
hook(filename => fetch(`.${sep}${relative(rootDir, filename)}`, '/'));

0 commit comments

Comments
 (0)