Skip to content

Commit

Permalink
Merge pull request #38 from michalkvasnicak/cache-and-circular-deps
Browse files Browse the repository at this point in the history
Cache and circular deps
  • Loading branch information
michalkvasnicak authored Mar 21, 2017
2 parents 02c7f94 + 5de9916 commit bea58d0
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 104 deletions.
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);
});
}

0 comments on commit bea58d0

Please sign in to comment.