Skip to content

Commit

Permalink
Merge pull request #4 from SassNinja/feature/groups-option
Browse files Browse the repository at this point in the history
groups option
  • Loading branch information
SassNinja authored Aug 8, 2018
2 parents 0cf1856 + 6c4aeaf commit 4444a6a
Show file tree
Hide file tree
Showing 13 changed files with 158 additions and 21 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,13 @@ if (window.innerWidth >= 960) {

## Options

There are only two options available which are both mandatory.
The following options are available.

| name | mandatory |
| ----------- | --------- |
| include | yes |
| queries | yes |
| groups | no |

### include

Expand All @@ -143,6 +149,17 @@ queries: {
}
```

### groups

By default the name of the extracted CSS file(s) is `[chunk]-[query]`. This option lets you map chunk names to a specific group name what results in `[group]-[query]`.
So the following code would generate a `app-desktop.css` instead of `exampleA-desktop.css` and `exampleB-desktop.css`. This can be useful when working with [splitChunks](https://webpack.js.org/plugins/split-chunks-plugin/).

```javascript
groups: {
app: ['exampleA', 'exampleB']
}
```

## Other Webpack Plugins

This plugin plays together well with the following other webpack plugins.
Expand Down
9 changes: 8 additions & 1 deletion src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ module.exports = class MediaQueryPlugin {
constructor(options) {
this.options = Object.assign({
include: [],
queries: {}
queries: {},
groups: {}
}, options);
}

Expand All @@ -41,6 +42,12 @@ module.exports = class MediaQueryPlugin {
// save options in store to provide to loader
store.options = this.options;

// reset store for every webpack instance
// required for unit testing because the store is shared
compiler.hooks.entryOption.tap(pluginName, () => {
store.resetMedia();
});

// if a filename has become invalid (watch mode)
// remove all related data from store
compiler.hooks.invalid.tap(pluginName, (fileName, changeTime) => {
Expand Down
19 changes: 16 additions & 3 deletions src/postcss.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,29 @@ module.exports = postcss.plugin('MediaQueryPostCSS', options => {
store.addMedia(name, css, options.path);
}

function getGroupName(name) {
const groupNames = Object.keys(options.groups);

for (let i = 0; i < groupNames.length; i++) {
const groupName = groupNames[i];
const group = options.groups[groupName];

if (group.indexOf(name) !== -1) {
return groupName;
}
}
}

return (css, result) => {

css.walkAtRules('media', atRule => {

const queryname = options.queries[atRule.params];

if (queryname) {
const name = `${options.basename}-${queryname}`;
const invalidIndex = store.invalid.indexOf(options.basename);

const groupName = getGroupName(options.basename);
const name = groupName ? `${groupName}-${queryname}` : `${options.basename}-${queryname}`;
addToStore(name, atRule);
atRule.remove();
}
Expand Down
5 changes: 4 additions & 1 deletion src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ class MediaQueryStore {
constructor() {
this.media = {};
this.options = {};
this.invalid = [];
}

addMedia(key, css, filename) {
Expand Down Expand Up @@ -40,6 +39,10 @@ class MediaQueryStore {
});
}

resetMedia() {
this.media = {};
}

getMediaKeys() {
return Object.keys(this.media);
}
Expand Down
3 changes: 2 additions & 1 deletion test/configs/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

module.exports = {
'only-javascript-output': require('./webpack/only-javascript-output'),
'external-css-output': require('./webpack/external-css-output')
'external-css-output': require('./webpack/external-css-output'),
'groups-option-output': require('./webpack/groups-option-output')
};
12 changes: 0 additions & 12 deletions test/configs/webpack/base.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@

const MediaQueryPlugin = require('../../../src');

module.exports = {
mode: 'development',
devtool: 'none',
entry: {
example: './test/data/example.js'
},
plugins: [
new MediaQueryPlugin({
include: [
'example'
],
queries: {
'print, screen and (max-width: 60em)': 'desktop'
}
})
],
stats: {
children: false
}
Expand Down
8 changes: 8 additions & 0 deletions test/configs/webpack/external-css-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ module.exports = merge(baseConfig, {
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new MediaQueryPlugin({
include: [
'example'
],
queries: {
'print, screen and (max-width: 60em)': 'desktop'
}
})
]
});
46 changes: 46 additions & 0 deletions test/configs/webpack/groups-option-output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const MediaQueryPlugin = require('../../../src');

module.exports = {
mode: 'development',
devtool: 'none',
entry: {
app: './test/data/app.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, `../../output/groups-option-output`)
},
module: {
rules: [
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
MediaQueryPlugin.loader,
'sass-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new MediaQueryPlugin({
include: true,
queries: {
'print, screen and (max-width: 60em)': 'desktop'
},
groups: {
app: ['exampleA', 'exampleB']
}
})
],
stats: {
children: false
}
};
12 changes: 11 additions & 1 deletion test/configs/webpack/only-javascript-output.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,15 @@ module.exports = merge(baseConfig, {
]
}
]
}
},
plugins: [
new MediaQueryPlugin({
include: [
'example'
],
queries: {
'print, screen and (max-width: 60em)': 'desktop'
}
})
]
});
4 changes: 4 additions & 0 deletions test/data/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

// testing groups option
import './exampleA.scss';
import './exampleB.scss';
8 changes: 8 additions & 0 deletions test/data/exampleA.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.foo {
color: red;
}
@media print, screen and (max-width: 60em) {
.foo {
color: green;
}
}
8 changes: 8 additions & 0 deletions test/data/exampleB.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.bar {
font-size: 1rem;
}
@media print, screen and (max-width: 60em) {
.bar {
font-size: 2rem;
}
}
26 changes: 25 additions & 1 deletion test/webpack-integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('Webpack Integration', function() {
});

// test mini-css-extract-plugin
it('should emit css files if using mini-css-extract-plugin', function(done) {
it('should emit css files when using mini-css-extract-plugin', function(done) {

const expected = {
assets: ['example.css', 'example.js', 'example-desktop.js', 'example-desktop.css'],
Expand All @@ -61,4 +61,28 @@ describe('Webpack Integration', function() {

});

it('should use groups option for extraxted file name', function(done) {

const expected = {
assets: ['app.css', 'app.js', 'app-desktop.css'],
chunks: ['app', 'app-desktop']
};

webpack(configs['groups-option-output'], (err, stats) => {

if (err)
done(err);
else if (stats.hasErrors())
done(stats.toString());

const assets = Object.keys(stats.compilation.assets);
const chunks = stats.compilation.chunks.map(chunk => chunk.id);

assert.deepEqual(assets, expected.assets);
assert.deepEqual(chunks, expected.chunks);
done();
});

});

});

0 comments on commit 4444a6a

Please sign in to comment.