From e09059cc62d073dde82d8ad0986143f18c8b5df3 Mon Sep 17 00:00:00 2001 From: Josh Johnston Date: Sat, 19 Sep 2015 16:42:56 +1000 Subject: [PATCH 1/3] update to allow passing a generateScopedName func directly, or fall back to default based on env --- README.md | 15 +++++++++++++++ index.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e82ec7b..8be238c 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ b.bundle(); - `output`: path to write the generated css. - `jsonOutput`: optional path to write a json manifest of classnames. - `use`: optional array of postcss plugins (by default we use the css-modules core plugins). +- `generateScopedName`: (API only) a function to override the default behaviour of creating locally scoped classnames. ## Using CSS Modules on the backend @@ -89,6 +90,20 @@ browserify -p [css-modulesify \ [postcss-modules-extract-imports]: https://github.com/css-modules/postcss-modules-extract-imports [postcss-modules-scope]: https://github.com/css-modules/postcss-modules-scope +## Building for production + +If you set `NODE_ENV=production` then `css-modulesify` will generate shorter (though less useful) classnames. + +You can also manually switch to short names by setting the `generateScopedName` option. Eg: + +``` +browserify.plugin(cssModulesify, { + rootDir: __dirname, + output: './dist/main.css', + generateScopedName: cssModulesify.generateShortName +}) +``` + ## Example An example implementation can be found [here](https://github.com/css-modules/browserify-demo). diff --git a/index.js b/index.js index 199971a..9f464fa 100644 --- a/index.js +++ b/index.js @@ -6,16 +6,51 @@ var FileSystemLoader = require('css-modules-loader-core/lib/file-system-loader') var assign = require('object-assign'); var stringHash = require('string-hash'); + +/* + Custom `generateScopedName` function for `postcss-modules-scope`. + Short names consisting of source hash and line number. +*/ +function generateShortName (name, filename, css) { + // first occurrence of the name + // TOOD: better match with regex + var i = css.indexOf('.' + name); + var numLines = css.substr(0, i).split(/[\r\n]/).length; + + var hash = stringHash(css).toString(36).substr(0, 5); + return '_' + name + '_' + hash + '_' + numLines; +} + /* Custom `generateScopedName` function for `postcss-modules-scope`. Appends a hash of the css source. */ -function createScopedNameFunc (plugin) { - var orig = plugin.generateScopedName; - return function (name, filename, css) { - var hash = stringHash(css).toString(36).substr(0, 5); - return orig.apply(plugin, arguments) + '___' + hash; - }; +function generateLongName (name, filename, css) { + var sanitisedPath = filename.replace(/\.[^\.\/\\]+$/, '') + .replace(/[\W_]+/g, '_') + .replace(/^_|_$/g, ''); + + var hash = stringHash(css).toString(36).substr(0, 5); + return '_' + sanitisedPath + '__' + name + '___' + hash; +} + +/* + Get the default plugins and apply options. +*/ +function getDefaultPlugins (options) { + var scope = Core.scope; + var customNameFunc = options.generateScopedName; + var defaultNameFunc = process.env.NODE_ENV === 'production' ? + generateShortName : + generateLongName; + + scope.generateScopedName = customNameFunc || defaultNameFunc; + + return [ + Core.localByDefault + , Core.extractImports + , scope + ]; } /* @@ -71,7 +106,7 @@ module.exports = function (browserify, options) { // PostCSS plugins passed to FileSystemLoader var plugins = options.use || options.u; if (!plugins) { - plugins = Core.defaultPlugins; + plugins = getDefaultPlugins(options); } else { if (typeof plugins === 'string') { @@ -95,7 +130,7 @@ module.exports = function (browserify, options) { if (name === 'postcss-modules-scope') { options[name] = options[name] || {}; if (!options[name].generateScopedName) { - options[name].generateScopedName = createScopedNameFunc(plugin); + options[name].generateScopedName = generateLongName; } } @@ -174,3 +209,6 @@ module.exports = function (browserify, options) { return browserify; }; + +module.exports.generateShortName = generateShortName; +module.exports.generateLongName = generateLongName; From 354200334d24a921664c05448e2d55dd632bde6f Mon Sep 17 00:00:00 2001 From: Josh Johnston Date: Sat, 19 Sep 2015 16:47:44 +1000 Subject: [PATCH 2/3] by default, long-names are descriptive enough without a file hash --- index.js | 3 +-- tests/index.js | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 9f464fa..292d25e 100644 --- a/index.js +++ b/index.js @@ -30,8 +30,7 @@ function generateLongName (name, filename, css) { .replace(/[\W_]+/g, '_') .replace(/^_|_$/g, ''); - var hash = stringHash(css).toString(36).substr(0, 5); - return '_' + sanitisedPath + '__' + name + '___' + hash; + return '_' + sanitisedPath + '__' + name; } /* diff --git a/tests/index.js b/tests/index.js index f69e93d..556b76d 100644 --- a/tests/index.js +++ b/tests/index.js @@ -29,6 +29,7 @@ function runTestCase (dir) { b.plugin(cssModulesify, { rootDir: path.join(casesDir, dir) , output: cssOutFilename + , generateScopedName: cssModulesify.generateLongName }); b.bundle(function (err) { From 50f3a4fe092992c267354002b4636b1d3f96b42b Mon Sep 17 00:00:00 2001 From: Josh Johnston Date: Sat, 19 Sep 2015 16:48:18 +1000 Subject: [PATCH 3/3] pass linting --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 292d25e..3c673af 100644 --- a/index.js +++ b/index.js @@ -25,7 +25,7 @@ function generateShortName (name, filename, css) { Custom `generateScopedName` function for `postcss-modules-scope`. Appends a hash of the css source. */ -function generateLongName (name, filename, css) { +function generateLongName (name, filename) { var sanitisedPath = filename.replace(/\.[^\.\/\\]+$/, '') .replace(/[\W_]+/g, '_') .replace(/^_|_$/g, '');