feat(@angular/cli): allow component css imports (#4667)

Fix #4285
This commit is contained in:
Filipe Silva 2017-02-14 19:29:47 +00:00 committed by Hans
parent 61fc099480
commit e55cb8237a
8 changed files with 84 additions and 164 deletions

View File

@ -55,6 +55,7 @@
"ember-cli-normalize-entity-name": "^1.0.0",
"ember-cli-string-utils": "^1.0.0",
"enhanced-resolve": "^3.1.0",
"exports-loader": "^0.6.3",
"extract-text-webpack-plugin": "^2.0.0-rc.3",
"file-loader": "^0.10.0",
"findup": "0.1.5",

View File

@ -14,7 +14,7 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin');
* Enumerate loaders and their dependencies from this file to let the dependency validator
* know they are used.
*
* require('raw-loader')
* require('exports-loader')
* require('style-loader')
* require('postcss-loader')
* require('css-loader')
@ -86,11 +86,20 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
}
];
const commonLoaders = ['postcss-loader'];
const commonLoaders = [
// css-loader doesn't support webpack.LoaderOptionsPlugin properly,
// so we need to add options in its query
`css-loader?${JSON.stringify({ sourceMap: cssSourceMap, importLoaders: 1 })}`,
'postcss-loader'
];
// load component css as raw strings
let rules: any = baseRules.map(({test, loaders}) => ({
exclude: globalStylePaths, test, loaders: ['raw-loader', ...commonLoaders, ...loaders]
exclude: globalStylePaths, test, loaders: [
'exports-loader?module.exports.toString()',
...commonLoaders,
...loaders
]
}));
// load global css as css files
@ -98,9 +107,6 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
rules.push(...baseRules.map(({test, loaders}) => ({
include: globalStylePaths, test, loaders: ExtractTextPlugin.extract({
use: [
// css-loader doesn't support webpack.LoaderOptionsPlugin properly,
// so we need to add options in its query
`css-loader?${JSON.stringify({ sourceMap: cssSourceMap })}`,
...commonLoaders,
...loaders
],

View File

@ -39,6 +39,7 @@
"diff": "^3.1.0",
"ember-cli-normalize-entity-name": "^1.0.0",
"ember-cli-string-utils": "^1.0.0",
"exports-loader": "^0.6.3",
"extract-text-webpack-plugin": "^2.0.0-rc.3",
"file-loader": "^0.10.0",
"findup": "0.1.5",

View File

@ -1,32 +0,0 @@
import {
writeMultipleFiles,
expectFileToMatch,
} from '../../../utils/fs';
import { expectToFail } from '../../../utils/utils';
import { ng } from '../../../utils/process';
import { stripIndents } from 'common-tags';
export default function () {
return writeMultipleFiles({
'src/styles.css': stripIndents`
@import './imported-styles.css';
body { background-color: blue; }
`,
'src/imported-styles.css': stripIndents`
p { background-color: red; }
`,
'src/app/app.component.css': stripIndents`
.outer {
.inner {
background: #fff;
}
}
`})
.then(() => ng('build', '--extract-css', '--sourcemap'))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/body\s*{\s*background-color: blue;\s*}/))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/p\s*{\s*background-color: red;\s*}/))
.then(() => expectToFail(() => expectFileToMatch('dist/styles.bundle.css', '"mappings":""')))
.then(() => expectFileToMatch('dist/main.bundle.js', /.outer.*.inner.*background:\s*#[fF]+/));
}

View File

@ -0,0 +1,70 @@
import {
writeMultipleFiles,
deleteFile,
expectFileToMatch,
replaceInFile
} from '../../../utils/fs';
import { expectToFail } from '../../../utils/utils';
import { ng } from '../../../utils/process';
import { stripIndents } from 'common-tags';
import { updateJsonFile } from '../../../utils/project';
export default function () {
const extensions = ['css', 'scss', 'less', 'styl'];
let promise = Promise.resolve();
extensions.forEach(ext => {
promise = promise.then(() => {
return writeMultipleFiles({
[`src/styles.${ext}`]: stripIndents`
@import './imported-styles.${ext}';
body { background-color: #00f; }
`,
[`src/imported-styles.${ext}`]: stripIndents`
p { background-color: #f00; }
`,
[`src/app/app.component.${ext}`]: stripIndents`
@import './imported-component-styles.${ext}';
.outer {
.inner {
background: #fff;
}
}
`,
[`src/app/imported-component-styles.${ext}`]: stripIndents`
h1 { background: #000; }
`})
// change files to use preprocessor
.then(() => updateJsonFile('angular-cli.json', configJson => {
const app = configJson['apps'][0];
app['styles'] = [`styles.${ext}`];
}))
.then(() => replaceInFile('src/app/app.component.ts',
'./app.component.css', `./app.component.${ext}`))
// run build app
.then(() => ng('build', '--extract-css', '--sourcemap'))
// verify global styles
.then(() => expectFileToMatch('dist/styles.bundle.css',
/body\s*{\s*background-color: #00f;\s*}/))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/p\s*{\s*background-color: #f00;\s*}/))
// verify global styles sourcemap
.then(() => expectToFail(() =>
expectFileToMatch('dist/styles.bundle.css', '"mappings":""')))
// verify component styles
.then(() => expectFileToMatch('dist/main.bundle.js',
/.outer.*.inner.*background:\s*#[fF]+/))
.then(() => expectFileToMatch('dist/main.bundle.js',
/h1.*background:\s*#000+/))
// change files back
.then(() => updateJsonFile('angular-cli.json', configJson => {
const app = configJson['apps'][0];
app['styles'] = ['styles.css'];
}))
.then(() => replaceInFile('src/app/app.component.ts',
`./app.component.${ext}`, './app.component.css'));
});
});
return promise;
}

View File

@ -1,42 +0,0 @@
import {
writeMultipleFiles,
deleteFile,
expectFileToMatch,
replaceInFile
} from '../../../utils/fs';
import { expectToFail } from '../../../utils/utils';
import { ng } from '../../../utils/process';
import { stripIndents } from 'common-tags';
import { updateJsonFile } from '../../../utils/project';
export default function () {
return writeMultipleFiles({
'src/styles.less': stripIndents`
@import './imported-styles.less';
body { background-color: blue; }
`,
'src/imported-styles.less': stripIndents`
p { background-color: red; }
`,
'src/app/app.component.less': stripIndents`
.outer {
.inner {
background: #fff;
}
}
`})
.then(() => deleteFile('src/app/app.component.css'))
.then(() => updateJsonFile('angular-cli.json', configJson => {
const app = configJson['apps'][0];
app['styles'] = ['styles.less'];
}))
.then(() => replaceInFile('src/app/app.component.ts',
'./app.component.css', './app.component.less'))
.then(() => ng('build', '--extract-css', '--sourcemap'))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/body\s*{\s*background-color: blue;\s*}/))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/p\s*{\s*background-color: red;\s*}/))
.then(() => expectToFail(() => expectFileToMatch('dist/styles.bundle.css', '"mappings":""')))
.then(() => expectFileToMatch('dist/main.bundle.js', /.outer.*.inner.*background:\s*#[fF]+/));
}

View File

@ -1,42 +0,0 @@
import {
writeMultipleFiles,
deleteFile,
expectFileToMatch,
replaceInFile
} from '../../../utils/fs';
import { expectToFail } from '../../../utils/utils';
import { ng } from '../../../utils/process';
import { stripIndents } from 'common-tags';
import { updateJsonFile } from '../../../utils/project';
export default function () {
return writeMultipleFiles({
'src/styles.scss': stripIndents`
@import './imported-styles.scss';
body { background-color: blue; }
`,
'src/imported-styles.scss': stripIndents`
p { background-color: red; }
`,
'src/app/app.component.scss': stripIndents`
.outer {
.inner {
background: #fff;
}
}
`})
.then(() => deleteFile('src/app/app.component.css'))
.then(() => updateJsonFile('angular-cli.json', configJson => {
const app = configJson['apps'][0];
app['styles'] = ['styles.scss'];
}))
.then(() => replaceInFile('src/app/app.component.ts',
'./app.component.css', './app.component.scss'))
.then(() => ng('build', '--extract-css', '--sourcemap'))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/body\s*{\s*background-color: blue;\s*}/))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/p\s*{\s*background-color: red;\s*}/))
.then(() => expectToFail(() => expectFileToMatch('dist/styles.bundle.css', '"mappings":""')))
.then(() => expectFileToMatch('dist/main.bundle.js', /.outer.*.inner.*background:\s*#[fF]+/));
}

View File

@ -1,42 +0,0 @@
import {
writeMultipleFiles,
deleteFile,
expectFileToMatch,
replaceInFile
} from '../../../utils/fs';
import { expectToFail } from '../../../utils/utils';
import { ng } from '../../../utils/process';
import { stripIndents } from 'common-tags';
import { updateJsonFile } from '../../../utils/project';
export default function () {
return writeMultipleFiles({
'src/styles.styl': stripIndents`
@import './imported-styles.styl';
body { background-color: blue; }
`,
'src/imported-styles.styl': stripIndents`
p { background-color: red; }
`,
'src/app/app.component.styl': stripIndents`
.outer {
.inner {
background: #fff;
}
}
`})
.then(() => deleteFile('src/app/app.component.css'))
.then(() => updateJsonFile('angular-cli.json', configJson => {
const app = configJson['apps'][0];
app['styles'] = ['styles.styl'];
}))
.then(() => replaceInFile('src/app/app.component.ts',
'./app.component.css', './app.component.styl'))
.then(() => ng('build', '--extract-css', '--sourcemap'))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/body\s*{\s*background-color: #00f;\s*}/))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/p\s*{\s*background-color: #f00;\s*}/))
.then(() => expectToFail(() => expectFileToMatch('dist/styles.bundle.css', '"mappings":""')))
.then(() => expectFileToMatch('dist/main.bundle.js', /.outer.*.inner.*background:\s*#[fF]+/));
}