-
Notifications
You must be signed in to change notification settings - Fork 12k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(@angular/cli): fix css url processing (#4803)
Fixing component css in #4667 uncovered errors in CSS url processing. This PR correctly composes absolute urls when using `--base-href` and/or `--deploy-url`. It also fixes asset output on `--aot` mode. Fix #4778 Fix #4782 Fix #4806
- Loading branch information
1 parent
599d659
commit a2e819a
Showing
7 changed files
with
117 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
import * as webpack from 'webpack'; | ||
import * as path from 'path'; | ||
import { oneLineTrim } from 'common-tags'; | ||
import { | ||
SuppressExtractedTextChunksWebpackPlugin | ||
} from '../../plugins/suppress-entry-chunks-webpack-plugin'; | ||
import { extraEntryParser, getOutputHashFormat } from './utils'; | ||
import { WebpackConfigOptions } from '../webpack-config'; | ||
import { pluginArgs } from '../../tasks/eject'; | ||
import { pluginArgs, postcssArgs } from '../../tasks/eject'; | ||
|
||
const cssnano = require('cssnano'); | ||
const postcssUrl = require('postcss-url'); | ||
const autoprefixer = require('autoprefixer'); | ||
const ExtractTextPlugin = require('extract-text-webpack-plugin'); | ||
|
||
|
@@ -39,11 +41,35 @@ export function getStylesConfig(wco: WebpackConfigOptions) { | |
// https://github.com/webpack-contrib/style-loader#recommended-configuration | ||
const cssSourceMap = buildOptions.extractCss && buildOptions.sourcemap; | ||
|
||
// minify/optimize css in production | ||
// autoprefixer is always run separately so disable here | ||
const extraPostCssPlugins = buildOptions.target === 'production' | ||
? [cssnano({ safe: true, autoprefixer: false })] | ||
: []; | ||
// Minify/optimize css in production. | ||
const cssnanoPlugin = cssnano({ safe: true, autoprefixer: false }); | ||
|
||
// Convert absolute resource URLs to account for base-href and deploy-url. | ||
const baseHref = wco.buildOptions.baseHref; | ||
const deployUrl = wco.buildOptions.deployUrl; | ||
const postcssUrlOptions = { | ||
url: (URL: string) => { | ||
// Only convert absolute URLs, which CSS-Loader won't process into require(). | ||
if (!URL.startsWith('/')) { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
ValeryVS
Contributor
|
||
return URL; | ||
} | ||
// Join together base-href, deploy-url and the original URL. | ||
// Also dedupe multiple slashes into single ones. | ||
return `/${baseHref || ''}/${deployUrl || ''}/${URL}`.replace(/\/\/+/g, '/'); | ||
} | ||
}; | ||
const urlPlugin = postcssUrl(postcssUrlOptions); | ||
// We need to save baseHref and deployUrl for the Ejected webpack config to work (we reuse | ||
// the function defined above). | ||
(postcssUrlOptions as any).baseHref = baseHref; | ||
(postcssUrlOptions as any).deployUrl = deployUrl; | ||
// Save the original options as arguments for eject. | ||
urlPlugin[postcssArgs] = postcssUrlOptions; | ||
|
||
// PostCSS plugins. | ||
const postCssPlugins = [autoprefixer(), urlPlugin].concat( | ||
buildOptions.target === 'production' ? [cssnanoPlugin] : [] | ||
); | ||
|
||
// determine hashing format | ||
const hashFormat = getOutputHashFormat(buildOptions.outputHashing); | ||
|
@@ -141,7 +167,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) { | |
new webpack.LoaderOptionsPlugin({ | ||
sourceMap: cssSourceMap, | ||
options: { | ||
postcss: [autoprefixer()].concat(extraPostCssPlugins), | ||
postcss: postCssPlugins, | ||
// css-loader, stylus-loader don't support LoaderOptionsPlugin properly | ||
// options are in query instead | ||
sassLoader: { sourceMap: cssSourceMap, includePaths }, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,7 @@ const licenseReplacements = [ | |
// TODO(hansl): review these | ||
const ignoredPackages = [ | ||
'[email protected]', // MIT, but doesn't list it in package.json | ||
'[email protected]', // MIT, but doesn't list it in package.json | ||
'[email protected]', // Looks like MIT | ||
'[email protected]', // Looks like MIT | ||
'[email protected]', // Looks like MIT | ||
|
@@ -79,8 +80,10 @@ const ignoredPackages = [ | |
'[email protected]', // MIT, but doesn't list it in package.json | ||
'[email protected]', // BSD, but doesn't list it in package.json | ||
'[email protected]', // MIT, but doesn't list it in package.json | ||
'[email protected]', // BSD, but doesn't list it in package.json | ||
'undefined@undefined', // Test package with no name nor version. | ||
'[email protected]' // Looks like MIT | ||
'[email protected]', // Looks like MIT | ||
'[email protected]' // LGPL,MIT but has a broken licenses array | ||
]; | ||
|
||
const root = path.resolve(__dirname, '../'); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { ng } from '../../utils/process'; | ||
import { | ||
expectFileToMatch, | ||
expectFileToExist, | ||
writeMultipleFiles | ||
} from '../../utils/fs'; | ||
import { expectToFail } from '../../utils/utils'; | ||
|
||
const imgSvg = ` | ||
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> | ||
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /> | ||
</svg> | ||
`; | ||
|
||
export default function () { | ||
return Promise.resolve() | ||
// Verify absolute/relative paths in global/component css. | ||
.then(() => writeMultipleFiles({ | ||
'src/styles.css': ` | ||
h1 { background: url('/assets/global-img-absolute.svg'); } | ||
h2 { background: url('./assets/global-img-relative.svg'); } | ||
`, | ||
'src/app/app.component.css': ` | ||
h3 { background: url('/assets/component-img-absolute.svg'); } | ||
h4 { background: url('../assets/component-img-relative.svg'); } | ||
`, | ||
// Using SVGs because they are loaded via file-loader and thus never inlined. | ||
'src/assets/global-img-absolute.svg': imgSvg, | ||
'src/assets/global-img-relative.svg': imgSvg, | ||
'src/assets/component-img-absolute.svg': imgSvg, | ||
'src/assets/component-img-relative.svg': imgSvg | ||
})) | ||
.then(() => ng('build', '--extract-css', '--aot')) | ||
// Check paths are correctly generated. | ||
.then(() => expectFileToMatch('dist/styles.bundle.css', | ||
`url\('\/assets\/global-img-absolute\.svg'\)`)) | ||
.then(() => expectFileToMatch('dist/styles.bundle.css', 'url\(global-img-relative.svg\)')) | ||
This comment has been minimized.
Sorry, something went wrong.
ValeryVS
Contributor
|
||
.then(() => expectFileToMatch('dist/main.bundle.js', | ||
`url\(\\'\/assets\/component-img-absolute\.svg\\'\)`)) | ||
.then(() => expectFileToMatch('dist/main.bundle.js', 'url\(component-img-relative\.svg\)')) | ||
// Check files are correctly created. | ||
.then(() => expectToFail(() => expectFileToExist('dist/global-img-absolute.svg'))) | ||
.then(() => expectFileToExist('dist/global-img-relative.svg')) | ||
.then(() => expectToFail(() => expectFileToExist('dist/component-img-absolute.svg'))) | ||
.then(() => expectFileToExist('dist/component-img-relative.svg')) | ||
// Also check with base-href and deploy-url flags. | ||
.then(() => ng('build', '--base-href=/base/', '--deploy-url=deploy/', | ||
'--extract-css', '--aot')) | ||
.then(() => expectFileToMatch('dist/styles.bundle.css', | ||
`url\('\/base\/deploy\/assets\/global-img-absolute\.svg'\)`)) | ||
.then(() => expectFileToMatch('dist/styles.bundle.css', 'url\(global-img-relative.svg\)')) | ||
.then(() => expectFileToMatch('dist/main.bundle.js', | ||
`url\(\\'\/base\/deploy\/assets\/component-img-absolute\.svg\\'\)`)) | ||
.then(() => expectFileToMatch('dist/main.bundle.js', | ||
'url\(deploy/component-img-relative\.svg\)')); | ||
} |
please include both single and double slash