Skip to content

Commit 108976f

Browse files
🐛 fix path variable in extractCss.filename option, update README, closes #25
1 parent ad832f6 commit 108976f

14 files changed

+137
-59
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ To extract all files in a single directory, give an object:
161161
[
162162
"css-modules-transform", {
163163
"extractCss": {
164-
dir: "./dist/stylesheets/",
165-
relativeRoot: "./src/",
166-
filename: "[path]/[name].css"
164+
"dir": "./dist/stylesheets/",
165+
"relativeRoot": "./src/",
166+
"filename": "[path]/[name].css"
167167
}
168168
}
169169
]

src/index.js

+4-51
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
1-
import { resolve, dirname, basename, extname, isAbsolute, join, relative } from 'path';
2-
import { writeFileSync, appendFileSync } from 'fs';
3-
import mkdirp from 'mkdirp';
1+
import { resolve, dirname, isAbsolute } from 'path';
42

53
// options resolvers
64
import * as requireHooksOptions from './options_resolvers';
75

8-
const writeCssFile = (filename, content) => {
9-
mkdirp.sync(dirname(filename));
10-
writeFileSync(filename, content);
11-
};
12-
const appendCssFile = (filename, content) => {
13-
mkdirp.sync(dirname(filename));
14-
appendFileSync(filename, content);
15-
};
6+
// utils.
7+
import { extractCssFile } from './utils';
168

179
const defaultOptions = {
1810
generateScopedName: '[name]__[local]___[hash:base64:5]'
@@ -79,45 +71,6 @@ export default function transformCssModules({ types: t }) {
7971
styles: new Map()
8072
};
8173

82-
const extractCssFile = (filepath, css) => {
83-
const { extractCss = null } = state.opts;
84-
if (!extractCss) return null;
85-
86-
// this is the case where a single extractCss is requested
87-
if (typeof(extractCss) === 'string') {
88-
// If this is the first file, then we should replace
89-
// old content
90-
if (state.$$css.styles.size === 1) {
91-
return writeCssFile(extractCss, css);
92-
}
93-
// this should output in a single file.
94-
// Let's append the new file content.
95-
return appendCssFile(extractCss, css);
96-
}
97-
98-
// This is the case where each css file is written in
99-
// its own file.
100-
const {
101-
dir = 'dist',
102-
filename = '[name].css',
103-
relativeRoot = ''
104-
} = extractCss;
105-
106-
// Make css file narmpe relative to relativeRoot
107-
const relativePath = relative(
108-
resolve(process.cwd(), relativeRoot),
109-
filepath
110-
);
111-
const destination = join(
112-
resolve(process.cwd(), dir),
113-
filename
114-
)
115-
.replace(/\[name]/, basename(filepath, extname(filepath)))
116-
.replace(/\[path]/, relativePath);
117-
118-
writeCssFile(destination, css);
119-
};
120-
12174
const pushStylesCreator = (toWrap) => (css, filepath) => {
12275
let processed;
12376

@@ -129,7 +82,7 @@ export default function transformCssModules({ types: t }) {
12982

13083
if (!state.$$css.styles.has(filepath)) {
13184
state.$$css.styles.set(filepath, processed);
132-
extractCssFile(filepath, processed);
85+
extractCssFile(process.cwd(), filepath, processed, state);
13386
}
13487

13588
return processed;

src/utils/extractCssFile.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import writeCssFile from './writeCssFile';
2+
import { basename, dirname, extname, join, relative, resolve } from 'path';
3+
4+
export const PATH_VARIABLES = ['[path]', '[name]'];
5+
6+
/**
7+
* Extracts CSS to file
8+
*
9+
* @param {String} cwd
10+
* @param {String} filepath
11+
* @param {String} css
12+
* @param {Object} state
13+
* @returns {null}
14+
*/
15+
export default function extractCssFile(cwd, filepath, css, state) {
16+
const { extractCss = null } = state.opts;
17+
18+
if (!extractCss) {
19+
return null;
20+
}
21+
22+
// this is the case where a single extractCss is requested
23+
if (typeof(extractCss) === 'string') {
24+
// check if extractCss contains some from pattern variables, if yes throw!
25+
PATH_VARIABLES.forEach(VARIABLE => {
26+
if (extractCss.indexOf(VARIABLE) !== -1) {
27+
throw new Error('extractCss cannot contain variables');
28+
}
29+
});
30+
31+
// If this is the first file, then we should replace
32+
// old content
33+
if (state.$$css.styles.size === 1) {
34+
return writeCssFile(extractCss, css);
35+
}
36+
37+
// this should output in a single file.
38+
// Let's append the new file content.
39+
return writeCssFile(extractCss, css, true);
40+
}
41+
42+
// This is the case where each css file is written in
43+
// its own file.
44+
const {
45+
dir = 'dist',
46+
filename = '[name].css',
47+
relativeRoot = ''
48+
} = extractCss;
49+
50+
// check if filename contains at least [name] variable
51+
if (filename.indexOf('[name]') === -1) {
52+
throw new Error('[name] variable has to be used in extractCss.filename option');
53+
}
54+
55+
// Make css file name relative to relativeRoot
56+
const relativePath = relative(
57+
resolve(cwd, relativeRoot),
58+
filepath
59+
);
60+
61+
const destination = join(
62+
resolve(cwd, dir),
63+
filename
64+
)
65+
.replace(/\[name]/, basename(filepath, extname(filepath)))
66+
.replace(/\[path]/, dirname(relativePath));
67+
68+
writeCssFile(destination, css);
69+
}

src/utils/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
export { default as extractCssFile } from './extractCssFile';
12
export { default as isBoolean } from './isBoolean';
23
export { default as isFunction } from './isFunction';
34
export { default as isModulePath } from './isModulePath';
45
export { default as isPlainObject } from './isPlainObject';
56
export { default as isRegExp } from './isRegExp';
67
export { default as isString } from './isString';
78
export { default as requireLocalFileOrNodeModule } from './requireLocalFileOrNodeModule';
9+
export { default as writeCssFile } from './writeCssFile';

src/utils/writeCssFile.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import mkdirp from 'mkdirp';
2+
import { dirname } from 'path';
3+
import { appendFileSync, writeFileSync } from 'fs';
4+
5+
/**
6+
* Writes css file to given path (and creates directories)
7+
*
8+
* @param {String} path
9+
* @param {String} content
10+
* @param {Boolean} append
11+
*/
12+
export default function writeCssFile(path, content, append = false) {
13+
mkdirp.sync(dirname(path));
14+
15+
if (append) {
16+
appendFileSync(path, content);
17+
} else {
18+
writeFileSync(path, content);
19+
}
20+
}

test/css/child.css

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.line {
2+
display: inline;
3+
}

test/fixtures/extensions.expected.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
var css = {
4-
'className': 'styles__className___385m0 parent__block___33Sxl'
4+
'className': 'styles__className___385m0 parent__block___33Sxl child__line___3fweh'
55
};
66
var scss = {
77
'sassy': 'extensions__sassy___12Yag'

test/fixtures/extractcss.combined.expected.css

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
.child__line___3fweh {
2+
display: inline;
3+
}
14
.parent__block___33Sxl {
25
display: block;
36
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.child__line___3fweh {
2+
display: inline;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.child__line___3fweh {
2+
display: inline;
3+
}
4+
.parent__block___33Sxl {
5+
display: block;
6+
}

test/fixtures/import.expected.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
var _styles = {
4-
'className': 'styles__className___385m0 parent__block___33Sxl'
4+
'className': 'styles__className___385m0 parent__block___33Sxl child__line___3fweh'
55
};
66

77
var _styles2 = _interopRequireDefault(_styles);

test/fixtures/require.expected.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict';
22

33
var styles = {
4-
'className': 'styles__className___385m0 parent__block___33Sxl'
5-
};
4+
'className': 'styles__className___385m0 parent__block___33Sxl child__line___3fweh'
5+
};

test/index.spec.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,23 @@ describe('babel-plugin-css-modules-transform', () => {
126126
.to.be.equal(readExpected('fixtures/extractcss.styles.expected.css'));
127127
});
128128

129+
it('should write a multiple css files using import preserving directory structure', () => {
130+
expect(transform('fixtures/import.js', {
131+
extractCss: {
132+
dir: `${__dirname}/output/`,
133+
filename: '[path]/[name].css',
134+
relativeRoot: `${__dirname}`
135+
}
136+
}).code).to.be.equal(readExpected('fixtures/import.expected.js'));
137+
138+
expect(readExpected(`${__dirname}/output/parent.css`))
139+
.to.be.equal(readExpected('fixtures/extractcss.parent.expected.css'));
140+
expect(readExpected(`${__dirname}/output/styles.css`))
141+
.to.be.equal(readExpected('fixtures/extractcss.styles.expected.css'));
142+
expect(readExpected(`${__dirname}/output/css/child.css`))
143+
.to.be.equal(readExpected('fixtures/extractcss.css.child.expected.css'));
144+
});
145+
129146
it('should write a multiple css files using require', () => {
130147
expect(transform('fixtures/require.js', {
131148
extractCss: {
@@ -171,7 +188,7 @@ describe('babel-plugin-css-modules-transform', () => {
171188
stream.on('end', (err) => {
172189
if (err) return cb(err);
173190
expect(readExpected(`${__dirname}/output/combined.css`))
174-
.to.be.equal(readExpected('fixtures/extractcss.parent.expected.css'));
191+
.to.be.equal(readExpected('fixtures/extractcss.parent-combined.expected.css'));
175192

176193
return cb();
177194
});
@@ -269,6 +286,7 @@ describe('babel-plugin-css-modules-transform', () => {
269286
}
270287
}).code).to.be.equal(readExpected('fixtures/require.expected.js'));
271288
expect(called).to.be.deep.equal([
289+
'css/child.css',
272290
'parent.css',
273291
'styles.css'
274292
]);

test/parent.css

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.block {
2+
composes: line from './css/child.css';
23
display: block;
34
}

0 commit comments

Comments
 (0)