Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,33 +175,6 @@ To extract all files in a single directory, give an object:
Note that `relativeRoot` is used to resolve relative directory names, available
as `[path]` in `filename` pattern.

## Using a `babel-register`

Make sure you set `ignore` option of `babel-register` to ignore all files used by css-modules-require-hook to process your css files.

**Require `babel-register` only once otherwise it will fail**
**Be aware, you need to explicitly ignore `node_modules` if you set `ignore` option**

```js
require('babel-register')({
ignore: /(processCss\.js|node_modules)/ // regex matching all files used by css-modules-require-hook to process your css files
})
```

## Using in mocha

Create a js file with content

**Be aware, you need to explicitly ignore `node_modules` if you set `ignore` option**

```js
require('babel-register')({
ignore: /(processCss\.js|node_modules)/ // regex matching all files used by css-modules-require-hook to process your css files
})
```

and then set this file as a compiler `--compilers js:<name-of-your-file>.js`

## Alternatives

- [babel-plugin-transform-postcss](https://github.com/wbyoung/babel-plugin-transform-postcss) - which supports async plugins and does not depend on `css-modules-require-hook`.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "babel-plugin-css-modules-transform",
"version": "1.2.1",
"version": "1.2.3",
"description": "Transform required css modules so one can use generated class names.",
"main": "build/index.js",
"scripts": {
Expand Down
113 changes: 69 additions & 44 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default function transformCssModules({ types: t }) {

// is css modules require hook initialized?
let initialized = false;
// are we requiring a module for preprocessCss, processCss, etc?
// we don't want them to be transformed using this plugin
// because it will cause circular dependency in babel-node and babel-register process
let inProcessingFunction = false;

let matchExtensions = /\.css$/i;

Expand All @@ -63,61 +67,80 @@ export default function transformCssModules({ types: t }) {
);
}

return {
visitor: {
Program(path, state) {
if (initialized) {
return;
}

const currentConfig = { ...defaultOptions, ...state.opts };
// this is not a css-require-ook config
delete currentConfig.extractCss;

// match file extensions, speeds up transform by creating one
// RegExp ahead of execution time
matchExtensions = matcher(currentConfig.extensions);
const cssMap = new Map();
let thisPluginOptions = null;

// Add a space in current state for css filenames
state.$$css = {
styles: new Map()
};

const pushStylesCreator = (toWrap) => (css, filepath) => {
let processed;
const pluginApi = {
manipulateOptions(options) {
if (initialized || inProcessingFunction) {
return options;
}

if (typeof toWrap === 'function') {
processed = toWrap(css, filepath);
}
// find options for this plugin
// we have to use this hack because plugin.key does not have to be 'css-modules-transform'
// so we will identify it by comparing manipulateOptions
thisPluginOptions = options.plugins.filter(
([plugin]) => plugin.manipulateOptions === pluginApi.manipulateOptions
)[0][1];

if (typeof processed !== 'string') processed = css;
const currentConfig = { ...defaultOptions, ...thisPluginOptions };
// this is not a css-require-ook config
delete currentConfig.extractCss;

if (!state.$$css.styles.has(filepath)) {
state.$$css.styles.set(filepath, processed);
extractCssFile(process.cwd(), filepath, processed, state);
}
// match file extensions, speeds up transform by creating one
// RegExp ahead of execution time
matchExtensions = matcher(currentConfig.extensions);

return processed;
};
const pushStylesCreator = (toWrap) => (css, filepath) => {
let processed;

// resolve options
Object.keys(requireHooksOptions).forEach(key => {
// skip undefined options
if (currentConfig[key] === undefined) {
return;
}
if (typeof toWrap === 'function') {
processed = toWrap(css, filepath);
}

currentConfig[key] = requireHooksOptions[key](currentConfig[key], currentConfig);
});
if (typeof processed !== 'string') processed = css;

// wrap or define processCss function that collect generated css
currentConfig.processCss = pushStylesCreator(currentConfig.processCss);
// set css content only if is new
if (!cssMap.has(filepath) || cssMap.get(filepath) !== processed) {
cssMap.set(filepath, processed);
}

require('css-modules-require-hook')(currentConfig);
return processed;
};

initialized = true;
},
// resolve options
Object.keys(requireHooksOptions).forEach(key => {
// skip undefined options
if (currentConfig[key] === undefined) {
return;
}

inProcessingFunction = true;
currentConfig[key] = requireHooksOptions[key](currentConfig[key], currentConfig);
inProcessingFunction = false;
});

// wrap or define processCss function that collect generated css
currentConfig.processCss = pushStylesCreator(currentConfig.processCss);

require('css-modules-require-hook')(currentConfig);

initialized = true;

return options;
},
post() {
// extract css only if is this option set
if (thisPluginOptions && thisPluginOptions.extractCss) {
// always rewrite file :-/
extractCssFile(
process.cwd(),
cssMap,
thisPluginOptions.extractCss
);
}
},
visitor: {
// import styles from './style.css';
ImportDefaultSpecifier(path, { file }) {
const { value } = path.parentPath.node.source;
Expand Down Expand Up @@ -162,4 +185,6 @@ export default function transformCssModules({ types: t }) {
}
}
};

return pluginApi;
}
53 changes: 21 additions & 32 deletions src/utils/extractCssFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,11 @@ export const PATH_VARIABLES = ['[path]', '[name]'];
* Extracts CSS to file
*
* @param {String} cwd
* @param {String} filepath
* @param {String} css
* @param {Object} state
* @param {Map} cssMap
* @param {String|Object} extractCss
* @returns {null}
*/
export default function extractCssFile(cwd, filepath, css, state) {
const { extractCss = null } = state.opts;

if (!extractCss) {
return null;
}

export default function extractCssFile(cwd, cssMap, extractCss) {
// this is the case where a single extractCss is requested
if (typeof(extractCss) === 'string') {
// check if extractCss contains some from pattern variables, if yes throw!
Expand All @@ -28,15 +21,9 @@ export default function extractCssFile(cwd, filepath, css, state) {
}
});

// If this is the first file, then we should replace
// old content
if (state.$$css.styles.size === 1) {
return writeCssFile(extractCss, css);
}
const css = Array.from(cssMap.values()).join('');

// this should output in a single file.
// Let's append the new file content.
return writeCssFile(extractCss, css, true);
return writeCssFile(extractCss, css);
}

// This is the case where each css file is written in
Expand All @@ -52,18 +39,20 @@ export default function extractCssFile(cwd, filepath, css, state) {
throw new Error('[name] variable has to be used in extractCss.filename option');
}

// Make css file name relative to relativeRoot
const relativePath = relative(
resolve(cwd, relativeRoot),
filepath
);

const destination = join(
resolve(cwd, dir),
filename
)
.replace(/\[name]/, basename(filepath, extname(filepath)))
.replace(/\[path]/, dirname(relativePath));

writeCssFile(destination, css);
cssMap.forEach((css, filepath) => {
// Make css file name relative to relativeRoot
const relativePath = relative(
resolve(cwd, relativeRoot),
filepath
);

const destination = join(
resolve(cwd, dir),
filename
)
.replace(/\[name]/, basename(filepath, extname(filepath)))
.replace(/\[path]/, dirname(relativePath));

writeCssFile(destination, css);
});
}