@angular/cli
Version:
CLI tool for Angular
195 lines • 7.94 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const suppress_entry_chunks_webpack_plugin_1 = require("../../plugins/suppress-entry-chunks-webpack-plugin");
const utils_1 = require("./utils");
const eject_1 = require("../../tasks/eject");
const cssnano = require('cssnano');
const postcssUrl = require('postcss-url');
const autoprefixer = require('autoprefixer');
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('exports-loader')
* require('style-loader')
* require('postcss-loader')
* require('css-loader')
* require('stylus')
* require('stylus-loader')
* require('less')
* require('less-loader')
* require('node-sass')
* require('sass-loader')
*/
function getStylesConfig(wco) {
const { projectRoot, buildOptions, appConfig } = wco;
const appRoot = path.resolve(projectRoot, appConfig.root);
const entryPoints = {};
const globalStylePaths = [];
const extraPlugins = [];
// style-loader does not support sourcemaps without absolute publicPath, so it's
// better to disable them when not extracting css
// https://github.com/webpack-contrib/style-loader#recommended-configuration
const cssSourceMap = buildOptions.extractCss && buildOptions.sourcemaps;
// Minify/optimize css in production.
const minimizeCss = buildOptions.target === 'production';
// Convert absolute resource URLs to account for base-href and deploy-url.
const baseHref = wco.buildOptions.baseHref || '';
const deployUrl = wco.buildOptions.deployUrl || '';
const postcssPluginCreator = function () {
// safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193
const importantCommentRe = /@preserve|@license|[@#]\s*source(?:Mapping)?URL|^!/i;
const minimizeOptions = {
autoprefixer: false,
safe: true,
mergeLonghand: false,
discardComments: { remove: (comment) => !importantCommentRe.test(comment) }
};
return [
postcssUrl({
url: (URL) => {
// Only convert root relative URLs, which CSS-Loader won't process into require().
if (!URL.startsWith('/') || URL.startsWith('//')) {
return URL;
}
if (deployUrl.match(/:\/\//)) {
// If deployUrl contains a scheme, 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, '/');
}
}
}),
autoprefixer(),
].concat(minimizeCss ? [cssnano(minimizeOptions)] : []);
};
postcssPluginCreator[eject_1.postcssArgs] = {
variableImports: {
'autoprefixer': 'autoprefixer',
'postcss-url': 'postcssUrl',
'cssnano': 'cssnano'
},
variables: { minimizeCss, baseHref, deployUrl }
};
// determine hashing format
const hashFormat = utils_1.getOutputHashFormat(buildOptions.outputHashing);
// use includePaths from appConfig
const includePaths = [];
if (appConfig.stylePreprocessorOptions
&& appConfig.stylePreprocessorOptions.includePaths
&& appConfig.stylePreprocessorOptions.includePaths.length > 0) {
appConfig.stylePreprocessorOptions.includePaths.forEach((includePath) => includePaths.push(path.resolve(appRoot, includePath)));
}
// process global styles
if (appConfig.styles.length > 0) {
const globalStyles = utils_1.extraEntryParser(appConfig.styles, appRoot, 'styles');
// add style entry points
globalStyles.forEach(style => entryPoints[style.entry]
? entryPoints[style.entry].push(style.path)
: entryPoints[style.entry] = [style.path]);
// add global css paths
globalStylePaths.push(...globalStyles.map((style) => style.path));
}
// set base rules to derive final rules from
const baseRules = [
{ test: /\.css$/, use: [] },
{ test: /\.scss$|\.sass$/, use: [{
loader: 'sass-loader',
options: {
sourceMap: cssSourceMap,
// bootstrap-sass requires a minimum precision of 8
precision: 8,
includePaths
}
}]
},
{ test: /\.less$/, use: [{
loader: 'less-loader',
options: {
sourceMap: cssSourceMap
}
}]
},
{
test: /\.styl$/, use: [{
loader: 'stylus-loader',
options: {
sourceMap: cssSourceMap,
paths: includePaths
}
}]
}
];
const commonLoaders = [
{
loader: 'css-loader',
options: {
sourceMap: cssSourceMap,
importLoaders: 1
}
},
{
loader: 'postcss-loader',
options: {
// A non-function property is required to workaround a webpack option handling bug
ident: 'postcss',
plugins: postcssPluginCreator
}
}
];
// load component css as raw strings
const rules = baseRules.map(({ test, use }) => ({
exclude: globalStylePaths, test, use: [
'exports-loader?module.exports.toString()',
...commonLoaders,
...use
]
}));
// load global css as css files
if (globalStylePaths.length > 0) {
rules.push(...baseRules.map(({ test, use }) => {
const extractTextPlugin = {
use: [
...commonLoaders,
...use
],
// publicPath needed as a workaround https://github.com/angular/angular-cli/issues/4035
publicPath: ''
};
const ret = {
include: globalStylePaths,
test,
use: buildOptions.extractCss ? ExtractTextPlugin.extract(extractTextPlugin)
: ['style-loader', ...extractTextPlugin.use]
};
// Save the original options as arguments for eject.
if (buildOptions.extractCss) {
ret[eject_1.pluginArgs] = extractTextPlugin;
}
return ret;
}));
}
if (buildOptions.extractCss) {
// extract global css from js files into own css file
extraPlugins.push(new ExtractTextPlugin({ filename: `[name]${hashFormat.extract}.bundle.css` }));
// suppress empty .js files in css only entry points
extraPlugins.push(new suppress_entry_chunks_webpack_plugin_1.SuppressExtractedTextChunksWebpackPlugin());
}
return {
entry: entryPoints,
module: { rules },
plugins: [].concat(extraPlugins)
};
}
exports.getStylesConfig = getStylesConfig;
//# sourceMappingURL=/users/hansl/sources/angular-cli/models/webpack-configs/styles.js.map
;