diff --git a/package.json b/package.json index d4782435d725..cf3c116a9189 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/@angular/cli/models/webpack-configs/styles.ts b/packages/@angular/cli/models/webpack-configs/styles.ts index b3b89a3a0b3a..99976351b7ba 100644 --- a/packages/@angular/cli/models/webpack-configs/styles.ts +++ b/packages/@angular/cli/models/webpack-configs/styles.ts @@ -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 ], diff --git a/packages/@angular/cli/package.json b/packages/@angular/cli/package.json index 7d2dba146932..72bb50093118 100644 --- a/packages/@angular/cli/package.json +++ b/packages/@angular/cli/package.json @@ -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", diff --git a/tests/e2e/tests/build/styles/css.ts b/tests/e2e/tests/build/styles/css.ts deleted file mode 100644 index 2257df68d3b4..000000000000 --- a/tests/e2e/tests/build/styles/css.ts +++ /dev/null @@ -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]+/)); -} diff --git a/tests/e2e/tests/build/styles/imports.ts b/tests/e2e/tests/build/styles/imports.ts new file mode 100644 index 000000000000..a7ce2a17f859 --- /dev/null +++ b/tests/e2e/tests/build/styles/imports.ts @@ -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; +} diff --git a/tests/e2e/tests/build/styles/less.ts b/tests/e2e/tests/build/styles/less.ts deleted file mode 100644 index d23dbb6dcac5..000000000000 --- a/tests/e2e/tests/build/styles/less.ts +++ /dev/null @@ -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]+/)); -} diff --git a/tests/e2e/tests/build/styles/scss.ts b/tests/e2e/tests/build/styles/scss.ts deleted file mode 100644 index 5c04b4841e9e..000000000000 --- a/tests/e2e/tests/build/styles/scss.ts +++ /dev/null @@ -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]+/)); -} diff --git a/tests/e2e/tests/build/styles/stylus.ts b/tests/e2e/tests/build/styles/stylus.ts deleted file mode 100644 index 72f2aaf89477..000000000000 --- a/tests/e2e/tests/build/styles/stylus.ts +++ /dev/null @@ -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]+/)); -}