Skip to content

Commit

Permalink
Add classGenerator option
Browse files Browse the repository at this point in the history
  • Loading branch information
sndyuk committed Mar 29, 2021
1 parent c8bd3ac commit 54fd701
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 15 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@ ignorePrefixRegExp: '((hover|focus|xs|md|sm|lg|xl)[\\\\]*:)*',
```
In this case, `hover\:xs\:c-textbox__input` becomes `hover\:xs\:a`.

#### classGenerator
Override the default class name generator.

```js
// original: original class name
// opts: options of the plugin
// context: own context of the class generator(initial value is just an empty object)
classGenerator: (original, opts, context) => {
// return custom generated class name.
// Or return undefined if you want to leave it to the original behavior.
}
```

### Example
#### Source code
```html
Expand Down
22 changes: 17 additions & 5 deletions lib/classGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@ const acceptChars = 'abcdefghijklmnopqrstuvwxyz_-0123456789'.split('');
function ClassGenerator() {
this.newClassMap = {};
this.newClassSize = 0;
this.context = {}
}

function stripEscapeSequence(words) {
return words.replace(/\\/g, '');
}

ClassGenerator.prototype = {
generateClassName: function(original, opts) {
original = stripEscapeSequence(original);
const cn = this.newClassMap[original];
if (cn) return cn;

defaultClassGenerator: function() {
const chars = []
let rest = (this.newClassSize - (this.newClassSize % acceptPrefix.length)) / acceptPrefix.length
if (rest > 0) {
Expand All @@ -36,6 +33,21 @@ ClassGenerator.prototype = {
let prefixIndex = this.newClassSize % acceptPrefix.length

const newClassName = `${acceptPrefix[prefixIndex]}${chars.join('')}`
return newClassName;
},
generateClassName: function(original, opts) {
original = stripEscapeSequence(original);
const cn = this.newClassMap[original];
if (cn) return cn;

let newClassName;
if (opts.classGenerator) {
newClassName = opts.classGenerator(original, opts, this.context);
}
if (!newClassName) {
newClassName = this.defaultClassGenerator();
}

if (opts.reserveClassName && opts.reserveClassName.includes(newClassName)) {
if (opts.log) {
console.log(`The class name has been reserved. ${chalk.green(newClassName)}`);
Expand Down
12 changes: 5 additions & 7 deletions lib/optimizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ const { ReplaceSource } = require('webpack-sources');
const chalk = require('./chalk');
const ClassGenerator = require('./classGenerator');

const classGenerator = new ClassGenerator()

const validate = (opts) => {
const validate = (opts, classGenerator) => {
if (!opts.log) return;
for (let className in classGenerator.newClassMap) {
const c = classGenerator.newClassMap[className];
Expand All @@ -19,7 +17,7 @@ const validate = (opts) => {
}
};

const optimize = (chunk, compilation, opts) => chunk.files.forEach((file) => {
const optimize = (chunk, compilation, opts, classGenerator) => chunk.files.forEach((file) => {
let classnameRegex;
if (file.match(/.+\.css.*$/)) {
classnameRegex = new RegExp(`\\\.(${opts.classNameRegExp})`, 'g');
Expand Down Expand Up @@ -85,9 +83,9 @@ const optimize = (chunk, compilation, opts) => chunk.files.forEach((file) => {

const optimizer = (compiler, compilation, opts) => (chunks) => {
if (!opts.classNameRegExp) throw new Error("'classNameRegExp' option is required. e.g. '[c]-[a-z][a-zA-Z0-9_]*'");

chunks.forEach((chunk) => optimize(chunk, compilation, opts));
validate(opts);
const classGenerator = new ClassGenerator();
chunks.forEach((chunk) => optimize(chunk, compilation, opts, classGenerator));
validate(opts, classGenerator);
}

module.exports = optimizer;
26 changes: 25 additions & 1 deletion spec/BasicSpec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var path = require('path');
var fs = require('fs');
var webpack = require('webpack');
var rimraf = require('rimraf');
var webpack = require('webpack');
var webpackMajorVersion = Number(require('webpack/package.json').version.split('.')[0]);
if (webpackMajorVersion < 4) {
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
Expand Down Expand Up @@ -197,4 +197,28 @@ describe('MangleCssClassPlugin', () => {
expect(classNameWithEscape.name).toBe(classNameWithoutEscape.name);
done();
});

it('override class name generator', (done) => {
testPlugin({
entry: [path.join(__dirname, 'fixtures/case4.js')],
output: {
path: OUTPUT_DIR,
filename: 'case4.js',
},
plugins: [new MangleCssClassPlugin({
classNameRegExp: defaultCssClassRegExp,
log: true,
classGenerator: (original, opts, context) => {
if (!context.id) {
context.id = 1;
}
if (original.startsWith('c-')) {
const className = `c${context.id}`;
context.id++;
return className;
}
}
})]
}, ["<p class=\\\"c1\\\">hoge-a<div class=\\\"b c1\\\">CASE 4</div></p>"], done);
});
});
1 change: 1 addition & 0 deletions spec/fixtures/case4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const a = '<p class="c-a">hoge-a<div class="l-abc c-a">CASE 4</div></p>';
4 changes: 2 additions & 2 deletions spec/support/jasmine.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"spec_files": [
"**/*[sS]pec.js"
],
"stopSpecOnExpectationFailure": false,
"random": true
"stopSpecOnExpectationFailure": true,
"random": false
}

0 comments on commit 54fd701

Please sign in to comment.