1 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
2 | const merge = require('deepmerge');
|
3 |
|
4 | module.exports = (neutrino, opts = {}) => {
|
5 | const modules = opts.modules || true;
|
6 | const modulesTest = opts.modulesTest || neutrino.regexFromExtensions(['module.css']);
|
7 | const options = merge({
|
8 | test: neutrino.regexFromExtensions(['css']),
|
9 | ruleId: 'style',
|
10 | styleUseId: 'style',
|
11 | cssUseId: 'css',
|
12 | css: {
|
13 | importLoaders: opts.loaders ? opts.loaders.length : 0
|
14 | },
|
15 | style: {},
|
16 | hot: true,
|
17 | hotUseId: 'hot',
|
18 | modules,
|
19 | modulesTest,
|
20 | modulesSuffix: '-modules',
|
21 | exclude: modules && modulesTest,
|
22 | loaders: [],
|
23 | extractId: 'extract',
|
24 | extract: {
|
25 | plugin: {
|
26 | filename: neutrino.options.command === 'build' ? '[name].[contenthash].css' : '[name].css',
|
27 | ignoreOrder: opts.modules !== false,
|
28 | allChunks: true
|
29 | }
|
30 | }
|
31 | }, opts);
|
32 |
|
33 | const rules = [options];
|
34 |
|
35 | if (options.modules) {
|
36 | rules.push(
|
37 | merge(options, {
|
38 | test: options.modulesTest,
|
39 | exclude: options.modulesExclude,
|
40 | ruleId: `${options.ruleId}${options.modulesSuffix}`,
|
41 | styleUseId: `${options.styleUseId}${options.modulesSuffix}`,
|
42 | cssUseId: `${options.cssUseId}${options.modulesSuffix}`,
|
43 | hotUseId: `${options.hotUseId}${options.modulesSuffix}`,
|
44 | extractId: `${options.extractId}${options.modulesSuffix}`,
|
45 | css: {
|
46 | modules: options.modules
|
47 | }
|
48 | })
|
49 | );
|
50 | };
|
51 |
|
52 | rules.forEach(options => {
|
53 | const styleRule = neutrino.config.module.rule(options.ruleId);
|
54 | const loaders = [
|
55 | {
|
56 | loader: require.resolve('style-loader'),
|
57 | options: options.style,
|
58 | useId: options.styleUseId
|
59 | },
|
60 | {
|
61 | loader: require.resolve('css-loader'),
|
62 | options: options.css,
|
63 | useId: options.cssUseId
|
64 | },
|
65 | ...options.loaders
|
66 | ]
|
67 | .map((loader, index) => {
|
68 | const obj = typeof loader === 'object' ? loader : { loader };
|
69 |
|
70 | return Object.assign(obj, {
|
71 | useId: obj.useId || `${options.cssUseId}-${index}`
|
72 | });
|
73 | });
|
74 |
|
75 | loaders.forEach(loader => {
|
76 | styleRule
|
77 | .test(options.test)
|
78 | .when(options.exclude, rule => rule.exclude.add(options.exclude))
|
79 | .use(loader.useId)
|
80 | .loader(loader.loader)
|
81 | .when(loader.options, use => use.options(loader.options));
|
82 | });
|
83 |
|
84 | if (options.extract) {
|
85 | const styleEntries = styleRule.uses.entries();
|
86 | const useIds = Object.keys(styleEntries).filter(key => key !== options.styleUseId);
|
87 | const extractLoader = Object.assign({
|
88 | use: useIds.map(key => ({
|
89 | loader: styleEntries[key].get('loader'),
|
90 | options: styleEntries[key].get('options')
|
91 | })),
|
92 | fallback: {
|
93 | loader: styleEntries[options.styleUseId].get('loader'),
|
94 | options: styleEntries[options.styleUseId].get('options')
|
95 | }
|
96 | }, options.extract.loader || {});
|
97 |
|
98 | styleRule
|
99 | .uses
|
100 | .clear()
|
101 | .end()
|
102 | .when(options.hot, (rule) => {
|
103 | rule.use(options.hotUseId)
|
104 | .loader(require.resolve('css-hot-loader'))
|
105 | .when(options.hot !== true, use => use.options(options.hot));
|
106 | });
|
107 |
|
108 | ExtractTextPlugin
|
109 | .extract(extractLoader)
|
110 | .forEach(({ loader, options }) => {
|
111 | styleRule
|
112 | .use(loader)
|
113 | .loader(loader)
|
114 | .options(options);
|
115 | });
|
116 |
|
117 | neutrino.config
|
118 | .plugin(options.extractId)
|
119 | .use(ExtractTextPlugin, [options.extract.plugin]);
|
120 | }
|
121 | });
|
122 |
|
123 | };
|