Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions fixtures/vuejs-css-modules/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<div id="app" class="red" :class="$style.italic"></div>
</template>

<style>
.red {
color: red;
}
</style>

<style module>
.italic {
font-style: italic;
}
</style>
8 changes: 8 additions & 0 deletions fixtures/vuejs-css-modules/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Vue from 'vue'
import App from './App'

new Vue({
el: '#app',
template: '<App/>',
components: { App }
})
16 changes: 15 additions & 1 deletion lib/config-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,21 @@ class ConfigGenerator {
},
{
test: /\.css$/,
use: cssExtractLoaderUtil.prependLoaders(this.webpackConfig, cssLoaderUtil.getLoaders(this.webpackConfig))
oneOf: [
{
resourceQuery: /module/,
use: cssExtractLoaderUtil.prependLoaders(
this.webpackConfig,
cssLoaderUtil.getLoaders(this.webpackConfig, true)
)
},
{
use: cssExtractLoaderUtil.prependLoaders(
this.webpackConfig,
cssLoaderUtil.getLoaders(this.webpackConfig)
)
}
]
}
];

Expand Down
7 changes: 5 additions & 2 deletions lib/loaders/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ const applyOptionsCallback = require('../utils/apply-options-callback');
module.exports = {
/**
* @param {WebpackConfig} webpackConfig
* @param {boolean} useCssModules
* @return {Array} of loaders to use for CSS files
*/
getLoaders(webpackConfig) {
getLoaders(webpackConfig, useCssModules = false) {
const usePostCssLoader = webpackConfig.usePostCssLoader;

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

const cssLoaders = [
Expand Down
55 changes: 55 additions & 0 deletions test/functional.js
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,61 @@ module.exports = {
});
});

it('Vue.js supports CSS modules', (done) => {
const appDir = testSetup.createTestAppDir();
const config = testSetup.createWebpackConfig(appDir, 'www/build', 'dev');
config.enableSingleRuntimeChunk();
config.setPublicPath('/build');
config.addEntry('main', './vuejs-css-modules/main');
config.enableVueLoader();
config.enableSassLoader();
config.enableLessLoader();
config.configureCssLoader(options => {
// Remove hashes from local ident names
// since they are not always the same.
options.localIdentName = '[local]_foo';
});

testSetup.runWebpack(config, (webpackAssert) => {
expect(config.outputPath).to.be.a.directory().with.deep.files([
'main.js',
'main.css',
'manifest.json',
'entrypoints.json',
'runtime.js',
]);

// Standard CSS
webpackAssert.assertOutputFileContains(
'main.css',
'.red {'
);

// CSS modules
webpackAssert.assertOutputFileContains(
'main.css',
'.italic_foo {'
);

testSetup.requestTestPage(
path.join(config.getContext(), 'www'),
[
'build/runtime.js',
'build/main.js'
],
(browser) => {
// Standard CSS
browser.assert.hasClass('#app', 'red');

// CSS modules
browser.assert.hasClass('#app', 'italic_foo');

done();
}
);
});
});

it('Vue.js error when using non-activated loaders', (done) => {
const config = createWebpackConfig('www/build', 'dev');
config.setPublicPath('/build');
Expand Down
18 changes: 18 additions & 0 deletions test/loaders/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('loaders/css', () => {
expect(actualLoaders).to.have.lengthOf(1);
expect(actualLoaders[0].options.sourceMap).to.be.true;
expect(actualLoaders[0].options.minimize).to.be.false;
expect(actualLoaders[0].options.modules).to.be.false;
});

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

it('getLoaders() with options callback', () => {
Expand All @@ -56,6 +58,22 @@ describe('loaders/css', () => {
expect(actualLoaders).to.have.lengthOf(1);
expect(actualLoaders[0].options.minimize).to.be.true;
expect(actualLoaders[0].options.url).to.be.false;
expect(actualLoaders[0].options.modules).to.be.false;
});

it('getLoaders() with CSS modules enabled', () => {
const config = createConfig();

config.configureCssLoader(function(options) {
options.minimize = true;
options.url = false;
});

const actualLoaders = cssLoader.getLoaders(config, true);
expect(actualLoaders).to.have.lengthOf(1);
expect(actualLoaders[0].options.minimize).to.be.true;
expect(actualLoaders[0].options.url).to.be.false;
expect(actualLoaders[0].options.modules).to.be.true;
});

describe('getLoaders() with PostCSS', () => {
Expand Down