Skip to content
Closed
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
39 changes: 28 additions & 11 deletions docs/documentation/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ dead code elimination via UglifyJS.
Both `--dev`/`--target=development` and `--prod`/`--target=production` are 'meta' flags, that set other flags.
If you do not specify either you will get the `--dev` defaults.

Flag | `--dev` | `--prod`
--- | --- | ---
`--aot` | `false` | `true`
`--environment` | `dev` | `prod`
`--output-hashing` | `media` | `all`
`--sourcemaps` | `true` | `false`
`--extract-css` | `false` | `true`
`--named-chunks`   | `true` | `false`
`--build-optimizer` | `false` | `true` with AOT and Angular 5
Flag | `--dev` | `--prod`
--- | --- | ---
`--aot` | `false` | `true`
`--environment` | `dev` | `prod`
`--output-hashing` | `media` | `all`
`--sourcemaps` | `true` | `false`
`--extract-css` | `false` | `true`
`--named-chunks` | `true` | `false`
`--build-optimizer` | `false` | `true` with AOT and Angular 5

`--prod` also sets the following non-flaggable settings:
- Adds service worker if configured in `.angular-cli.json`.
Expand All @@ -100,7 +100,11 @@ code.
### CSS resources

Resources in CSS, such as images and fonts, will be copied over automatically as part of a build.
If a resource is less than 10kb it will also be inlined.
If a resource is less than 10kb it will also be inlined by default.

By using flaf `--inline-asset-max-size` it's possible to define the max size of the

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo "flag"

assets that have to be inlined. Negative values will result in no assets to be inlined.


You'll see these resources be outputted and fingerprinted at the root of `dist/`.

Expand Down Expand Up @@ -189,6 +193,19 @@ See https://github.com/angular/angular-cli/issues/7797 for details.
</p>
</details>

<details>
<summary>inline-asset-max-size</summary>
<p>
<code>--inline-asset-max-size</code>
</p>
<p>
Maximum size (in Kb) of assets to be inlined
</p>
<p>
Values: <code>-1</code> - must not inline any assets, <code>positive integer</code> - size in Kb of assets to inline
</p>
</details>

<details>
<summary>i18n-file</summary>
<p>
Expand Down Expand Up @@ -404,4 +421,4 @@ See https://github.com/angular/angular-cli/issues/7797 for details.
<p>
Extract all licenses in a separate file, in the case of production builds only.
</p>
</details>
</details>
5 changes: 5 additions & 0 deletions packages/@angular/cli/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ export const baseBuildCommandOptions: any = [
aliases: ['ec'],
description: 'Extract css from global styles onto css files instead of js ones.'
},
{
name: 'inline-asset-max-size',
type: Number,
description: 'Maximum size (in Kb) of assets to be inlined'
},
{
name: 'watch',
type: Boolean,
Expand Down
1 change: 1 addition & 0 deletions packages/@angular/cli/models/build-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface BuildOptions {
locale?: string;
missingTranslation?: string;
extractCss?: boolean;
inlineAssetMaxSize?: number;
bundleDependencies?: 'none' | 'all';
watch?: boolean;
outputHashing?: string;
Expand Down
77 changes: 49 additions & 28 deletions packages/@angular/cli/models/webpack-configs/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,39 +44,60 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
const baseHref = wco.buildOptions.baseHref || '';
const deployUrl = wco.buildOptions.deployUrl || '';

const getPostcssUrlConfig = function() {
interface PostcssUrlConfig {
filter({ url }: { url: string}): boolean;
url: string | Function;
maxSize?: number;
}

let config: PostcssUrlConfig[] = [];

const convertRelativeUrlConfig: PostcssUrlConfig = {
// Only convert root relative URLs, which CSS-Loader won't process into require().
filter: ({ url }: { url: string}) => url.startsWith('/') && !url.startsWith('//'),
url: ({ url }: { url: string }) => {
if (deployUrl.match(/:\/\//) || deployUrl.startsWith('/')) {
// If deployUrl is absolute or root relative, ignore baseHref & use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${url}`;
} else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${url}`.replace(/\/\/+/g, '/');
} else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${url}`.replace(/\/\/+/g, '/');
}
}
};

config.push(convertRelativeUrlConfig);

// Do not inline any assets if the inline-asset-max-size option is negative
if (!buildOptions.inlineAssetMaxSize || buildOptions.inlineAssetMaxSize >= 0) {
const inlineAssetsConfig: PostcssUrlConfig = {
// TODO: inline .cur if not supporting IE (use browserslist to check)
filter: (asset: any) => !asset.hash && !asset.absolutePath.endsWith('.cur'),
url: 'inline',
// NOTE: maxSize is in KB
maxSize: Number.isInteger(buildOptions.inlineAssetMaxSize) ?
buildOptions.inlineAssetMaxSize : 10,
};

config.push(inlineAssetsConfig);
}

return config;
};

const postcssPluginCreator = function() {
return [
postcssUrl({
filter: ({ url }: { url: string }) => url.startsWith('~'),
url: ({ url }: { url: string }) => path.join(projectRoot, 'node_modules', url.substr(1)),
}),
postcssUrl([
{
// Only convert root relative URLs, which CSS-Loader won't process into require().
filter: ({ url }: { url: string }) => url.startsWith('/') && !url.startsWith('//'),
url: ({ url }: { url: string }) => {
if (deployUrl.match(/:\/\//) || deployUrl.startsWith('/')) {
// If deployUrl is absolute or root relative, ignore baseHref & use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${url}`;
} else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${url}`.replace(/\/\/+/g, '/');
} else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${url}`.replace(/\/\/+/g, '/');
}
}
},
{
// TODO: inline .cur if not supporting IE (use browserslist to check)
filter: (asset: any) => !asset.hash && !asset.absolutePath.endsWith('.cur'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of the extra function (which is breaking the eject command). Add a condition to the filter here.
Also the semantics of the option values should be changed. A maximum size of zero (0) means nothing should be inlined. Infinity would mean everything should be inlined.

url: 'inline',
// NOTE: maxSize is in KB
maxSize: 10
}
]),
postcssUrl(getPostcssUrlConfig()),
autoprefixer(),
customProperties({ preserve: true })
];
Expand Down Expand Up @@ -195,7 +216,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
const ret: any = {
include: globalStylePaths,
test,
        use: buildOptions.extractCss ? ExtractTextPlugin.extract(extractTextPlugin)
use: buildOptions.extractCss ? ExtractTextPlugin.extract(extractTextPlugin)
: ['style-loader', ...extractTextPlugin.use]
};
// Save the original options as arguments for eject.
Expand Down
51 changes: 51 additions & 0 deletions tests/e2e/tests/build/styles/inline-asset-max-size.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ng } from '../../../utils/process';
import {
expectFileToMatch,
expectFileMatchToExist,
writeMultipleFiles
} from '../../../utils/fs';
import { copyProjectAsset } from '../../../utils/assets';
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()
.then(() => writeMultipleFiles({
'src/styles.css': `
h1 { background: url('./assets/large.png'); }
h2 { background: url('./assets/small.svg'); }
p { background: url('./assets/small-id.svg#testID'); }
`,
'src/app/app.component.css': `
h3 { background: url('../assets/small.svg'); }
h4 { background: url('../assets/large.png'); }
`,
'src/assets/small.svg': imgSvg,
'src/assets/small-id.svg': imgSvg
}))
.then(() => copyProjectAsset('images/spectrum.png', './assets/large.png'))
.then(() => ng('build', '--extract-css', '--inline-asset-max-size=-1', '--aot'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests for inlining all resources and at an arbitrary non-default value would also be needed.

// Check paths are correctly generated.
.then(() => expectFileToMatch('dist/styles.bundle.css',
/url\([\'"]?large\.[0-9a-f]{20}\.png[\'"]?\)/))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/url\([\'"]?small\.[0-9a-f]{20}\.svg[\'"]?\)/))
.then(() => expectFileToMatch('dist/styles.bundle.css',
/url\([\'"]?small-id\.[0-9a-f]{20}\.svg#testID[\'"]?\)/))
.then(() => expectFileToMatch('dist/main.bundle.js',
/url\([\'"]?small\.[0-9a-f]{20}\.svg[\'"]?\)/))
.then(() => expectFileToMatch('dist/main.bundle.js',
/url\([\'"]?large\.[0-9a-f]{20}\.png[\'"]?\)/))
// Check if no inline images have been generated
.then(() => expectToFail(() => expectFileToMatch('dist/styles.bundle.css',
/url\(\\?[\'"]data:image\/svg\+xml/)))
// Check files are correctly created.
.then(() => expectFileMatchToExist('./dist', /large\.[0-9a-f]{20}\.png/))
.then(() => expectFileMatchToExist('./dist', /small\.[0-9a-f]{20}\.svg/))
.then(() => expectFileMatchToExist('./dist', /small-id\.[0-9a-f]{20}\.svg/));
}