forked from angular/angular-cli
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathstyles.ts
143 lines (128 loc) · 4.95 KB
/
styles.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import * as webpack from 'webpack';
import * as path from 'path';
import {
SuppressExtractedTextChunksWebpackPlugin
} from '../../plugins/suppress-entry-chunks-webpack-plugin';
import { extraEntryParser, getOutputHashFormat } from './utils';
import { WebpackConfigOptions } from '../webpack-config';
const cssnano = require('cssnano');
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('raw-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')
*/
export function getStylesConfig(wco: WebpackConfigOptions) {
const { projectRoot, buildOptions, appConfig } = wco;
const appRoot = path.resolve(projectRoot, appConfig.root);
const entryPoints: { [key: string]: string[] } = {};
const globalStylePaths: string[] = [];
const extraPlugins: any[] = [];
// 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.sourcemap;
// minify/optimize css in production
// autoprefixer is always run separately so disable here
const extraPostCssPlugins = buildOptions.target === 'production'
? [cssnano({ safe: true, autoprefixer: false })]
: [];
// determine hashing format
const hashFormat = getOutputHashFormat(buildOptions.outputHashing);
// use includePaths from appConfig
const includePaths: string[] = [];
if (appConfig.stylePreprocessorOptions
&& appConfig.stylePreprocessorOptions.includePaths
&& appConfig.stylePreprocessorOptions.includePaths.length > 0
) {
appConfig.stylePreprocessorOptions.includePaths.forEach((includePath: string) =>
includePaths.push(path.resolve(appRoot, includePath)));
}
// process global styles
if (appConfig.styles.length > 0) {
const globalStyles = 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$/, loaders: [] },
{ test: /\.scss$|\.sass$/, loaders: ['sass-loader'] },
{ test: /\.less$/, loaders: ['less-loader'] },
// stylus-loader doesn't support webpack.LoaderOptionsPlugin properly,
// so we need to add options in its query
{
test: /\.styl$/, loaders: [`stylus-loader?${JSON.stringify({
sourceMap: cssSourceMap,
paths: includePaths
})}`]
}
];
const commonLoaders = ['postcss-loader'];
// load component css as raw strings
let rules: any = baseRules.map(({test, loaders}) => ({
exclude: globalStylePaths, test, loaders: ['raw-loader', ...commonLoaders, ...loaders]
}));
// load global css as css files
if (globalStylePaths.length > 0) {
rules.push(...baseRules.map(({test, loaders}) => ({
include: globalStylePaths, test, loaders: ExtractTextPlugin.extract({
loader: [
// 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
],
fallbackLoader: 'style-loader',
// publicPath needed as a workaround https://github.com/angular/angular-cli/issues/4035
publicPath: ''
})
})));
}
// supress empty .js files in css only entry points
if (buildOptions.extractCss) {
extraPlugins.push(new SuppressExtractedTextChunksWebpackPlugin());
}
return {
entry: entryPoints,
module: { rules },
plugins: [
// extract global css from js files into own css file
new ExtractTextPlugin({
filename: `[name]${hashFormat.extract}.bundle.css`,
disable: !buildOptions.extractCss
}),
new webpack.LoaderOptionsPlugin({
sourceMap: cssSourceMap,
options: {
postcss: [autoprefixer()].concat(extraPostCssPlugins),
// css-loader, stylus-loader don't support LoaderOptionsPlugin properly
// options are in query instead
sassLoader: { sourceMap: cssSourceMap, includePaths },
// less-loader doesn't support paths
lessLoader: { sourceMap: cssSourceMap },
// context needed as a workaround https://github.com/jtangelder/sass-loader/issues/285
context: projectRoot,
},
})
].concat(extraPlugins)
};
}