Skip to content

Commit 6867443

Browse files
Ryan WeaverRyan Weaver
Ryan Weaver
authored and
Ryan Weaver
committed
bug #508 Support CSS modules in Vue.js projects by default (Lyrkan)
This PR was merged into the master branch. Discussion ---------- Support CSS modules in Vue.js projects by default With the current version of Encore you are able to either: * only use standard CSS (default behavior) * only use CSS modules (by calling `Encore.configureCssLoader()`) This PR should help detecting when `<style module>` is used and enabling css modules accordingly (fixes #460). **Reference:** https://vue-loader.vuejs.org/guide/css-modules.html#opt-in-usage Commits ------- 356e538 Support CSS modules in Vue.js projects by default
2 parents 244141c + 356e538 commit 6867443

File tree

6 files changed

+116
-3
lines changed

6 files changed

+116
-3
lines changed

fixtures/vuejs-css-modules/App.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<div id="app" class="red" :class="$style.italic"></div>
3+
</template>
4+
5+
<style>
6+
.red {
7+
color: red;
8+
}
9+
</style>
10+
11+
<style module>
12+
.italic {
13+
font-style: italic;
14+
}
15+
</style>

fixtures/vuejs-css-modules/main.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Vue from 'vue'
2+
import App from './App'
3+
4+
new Vue({
5+
el: '#app',
6+
template: '<App/>',
7+
components: { App }
8+
})

lib/config-generator.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,21 @@ class ConfigGenerator {
229229
},
230230
{
231231
test: /\.css$/,
232-
use: cssExtractLoaderUtil.prependLoaders(this.webpackConfig, cssLoaderUtil.getLoaders(this.webpackConfig))
232+
oneOf: [
233+
{
234+
resourceQuery: /module/,
235+
use: cssExtractLoaderUtil.prependLoaders(
236+
this.webpackConfig,
237+
cssLoaderUtil.getLoaders(this.webpackConfig, true)
238+
)
239+
},
240+
{
241+
use: cssExtractLoaderUtil.prependLoaders(
242+
this.webpackConfig,
243+
cssLoaderUtil.getLoaders(this.webpackConfig)
244+
)
245+
}
246+
]
233247
}
234248
];
235249

lib/loaders/css.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ const applyOptionsCallback = require('../utils/apply-options-callback');
1515
module.exports = {
1616
/**
1717
* @param {WebpackConfig} webpackConfig
18+
* @param {boolean} useCssModules
1819
* @return {Array} of loaders to use for CSS files
1920
*/
20-
getLoaders(webpackConfig) {
21+
getLoaders(webpackConfig, useCssModules = false) {
2122
const usePostCssLoader = webpackConfig.usePostCssLoader;
2223

2324
const options = {
@@ -27,7 +28,9 @@ module.exports = {
2728
// be applied to those imports? This defaults to 0. When postcss-loader
2829
// is used, we set it to 1, so that postcss-loader is applied
2930
// to @import resources.
30-
importLoaders: usePostCssLoader ? 1 : 0
31+
importLoaders: usePostCssLoader ? 1 : 0,
32+
modules: useCssModules,
33+
localIdentName: '[local]_[hash:base64:5]',
3134
};
3235

3336
const cssLoaders = [

test/functional.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,61 @@ module.exports = {
13541354
});
13551355
});
13561356

1357+
it('Vue.js supports CSS modules', (done) => {
1358+
const appDir = testSetup.createTestAppDir();
1359+
const config = testSetup.createWebpackConfig(appDir, 'www/build', 'dev');
1360+
config.enableSingleRuntimeChunk();
1361+
config.setPublicPath('/build');
1362+
config.addEntry('main', './vuejs-css-modules/main');
1363+
config.enableVueLoader();
1364+
config.enableSassLoader();
1365+
config.enableLessLoader();
1366+
config.configureCssLoader(options => {
1367+
// Remove hashes from local ident names
1368+
// since they are not always the same.
1369+
options.localIdentName = '[local]_foo';
1370+
});
1371+
1372+
testSetup.runWebpack(config, (webpackAssert) => {
1373+
expect(config.outputPath).to.be.a.directory().with.deep.files([
1374+
'main.js',
1375+
'main.css',
1376+
'manifest.json',
1377+
'entrypoints.json',
1378+
'runtime.js',
1379+
]);
1380+
1381+
// Standard CSS
1382+
webpackAssert.assertOutputFileContains(
1383+
'main.css',
1384+
'.red {'
1385+
);
1386+
1387+
// CSS modules
1388+
webpackAssert.assertOutputFileContains(
1389+
'main.css',
1390+
'.italic_foo {'
1391+
);
1392+
1393+
testSetup.requestTestPage(
1394+
path.join(config.getContext(), 'www'),
1395+
[
1396+
'build/runtime.js',
1397+
'build/main.js'
1398+
],
1399+
(browser) => {
1400+
// Standard CSS
1401+
browser.assert.hasClass('#app', 'red');
1402+
1403+
// CSS modules
1404+
browser.assert.hasClass('#app', 'italic_foo');
1405+
1406+
done();
1407+
}
1408+
);
1409+
});
1410+
});
1411+
13571412
it('Vue.js error when using non-activated loaders', (done) => {
13581413
const config = createWebpackConfig('www/build', 'dev');
13591414
config.setPublicPath('/build');

test/loaders/css.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ describe('loaders/css', () => {
3131
expect(actualLoaders).to.have.lengthOf(1);
3232
expect(actualLoaders[0].options.sourceMap).to.be.true;
3333
expect(actualLoaders[0].options.minimize).to.be.false;
34+
expect(actualLoaders[0].options.modules).to.be.false;
3435
});
3536

3637
it('getLoaders() for production', () => {
@@ -42,6 +43,7 @@ describe('loaders/css', () => {
4243
expect(actualLoaders).to.have.lengthOf(1);
4344
expect(actualLoaders[0].options.sourceMap).to.be.false;
4445
expect(actualLoaders[0].options.minimize).to.be.true;
46+
expect(actualLoaders[0].options.modules).to.be.false;
4547
});
4648

4749
it('getLoaders() with options callback', () => {
@@ -56,6 +58,22 @@ describe('loaders/css', () => {
5658
expect(actualLoaders).to.have.lengthOf(1);
5759
expect(actualLoaders[0].options.minimize).to.be.true;
5860
expect(actualLoaders[0].options.url).to.be.false;
61+
expect(actualLoaders[0].options.modules).to.be.false;
62+
});
63+
64+
it('getLoaders() with CSS modules enabled', () => {
65+
const config = createConfig();
66+
67+
config.configureCssLoader(function(options) {
68+
options.minimize = true;
69+
options.url = false;
70+
});
71+
72+
const actualLoaders = cssLoader.getLoaders(config, true);
73+
expect(actualLoaders).to.have.lengthOf(1);
74+
expect(actualLoaders[0].options.minimize).to.be.true;
75+
expect(actualLoaders[0].options.url).to.be.false;
76+
expect(actualLoaders[0].options.modules).to.be.true;
5977
});
6078

6179
describe('getLoaders() with PostCSS', () => {

0 commit comments

Comments
 (0)