|
1 | 1 | const mix = require("laravel-mix");
|
2 | 2 |
|
3 |
| -class VueCssModule { |
| 3 | +class VueCssModules { |
4 | 4 | /**
|
5 | 5 | * Register the component.
|
6 | 6 | *
|
7 |
| - * When your component is called, all user parameters |
8 |
| - * will be passed to this method. |
9 |
| - * |
10 |
| - * Ex: register(src, output) {} |
11 |
| - * Ex: mix.yourPlugin('src/path', 'output/path'); |
12 |
| - * |
13 |
| - * @param {*} ...params |
14 |
| - * @return {void} |
15 |
| - * |
| 7 | + * @param {Object} options |
| 8 | + * @param {Boolean} [options.oneOf] |
| 9 | + * @param {Boolean} [options.preProcessor] |
| 10 | + * @param {String} [options.localIdentNameType] |
| 11 | + * @param {Object} [options.cssLoaderOptions] |
16 | 12 | */
|
17 |
| - register({ |
18 |
| - localIdentName = "[local]_[hash:base64:8]", |
19 |
| - mode = "global", |
20 |
| - oneOf = false, |
21 |
| - sass = false, |
22 |
| - } = {}) { |
23 |
| - this.localIdentName = localIdentName; |
24 |
| - this.mode = mode; |
25 |
| - this.oneOf = oneOf; |
26 |
| - this.sass = sass; |
| 13 | + register(options = {}) { |
| 14 | + const config = { |
| 15 | + modules: true, // {Boolean\|String\|Object} |
| 16 | + sourceMap: false, // {Boolean} |
| 17 | + importLoaders: 1, // {Number} // webpackDefault: 0 // laravel-mix default: 1 |
| 18 | + esModule: true, // {Boolean}, |
| 19 | + localIdentName: options.cssLoaderOptions.localIdentName |
| 20 | + ? options.cssLoaderOptions.localIdentName |
| 21 | + : this.defaultLocalIdentName(options.localIdentNameType), // {String} |
| 22 | + }; |
| 23 | + |
| 24 | + const cssLoaderOptions = { |
| 25 | + ...config, |
| 26 | + ...options.cssLoaderOptions, |
| 27 | + }; |
| 28 | + |
| 29 | + delete options.cssLoaderOptions; |
| 30 | + |
| 31 | + this.options = Object.assign( |
| 32 | + { |
| 33 | + oneOf: false, |
| 34 | + preProcessor: true, |
| 35 | + exclude: [], |
| 36 | + cssLoaderOptions: cssLoaderOptions, |
| 37 | + }, |
| 38 | + options |
| 39 | + ); |
| 40 | + |
| 41 | + console.log(this.options); |
27 | 42 | }
|
28 | 43 |
|
29 | 44 | /**
|
30 | 45 | * Override the generated webpack configuration.
|
31 | 46 | *
|
32 |
| - * @param {Object} webpackConfig |
33 |
| - * @return {void} |
| 47 | + * @param {Object} config |
34 | 48 | */
|
35 |
| - webpackConfig(webpackConfig) { |
36 |
| - webpackConfig.module.rules = webpackConfig.module.rules.map((rule) => { |
37 |
| - if (!rule.loaders) { |
38 |
| - return rule; |
39 |
| - } |
| 49 | + webpackConfig(config) { |
| 50 | + // for css-loader |
| 51 | + const cssLoaders = config.module.rules.find( |
| 52 | + (rule) => rule.test.toString() === "/\\.css$/" |
| 53 | + ); |
| 54 | + |
| 55 | + if (this.options.oneOf) this.handleOneOfCss(cssLoaders); |
| 56 | + else this.handleCss(cssLoaders); |
40 | 57 |
|
41 |
| - const sass = rule.loaders.find( |
42 |
| - (loader) => loader.loader === "sass-loader" |
| 58 | + // only if pre-processor activated || default is active |
| 59 | + if (this.options.preProcessor) { |
| 60 | + // for sass-loader |
| 61 | + const sassLoaders = config.module.rules.find( |
| 62 | + (rule) => rule.test.toString() === "/\\.scss$/" |
43 | 63 | );
|
44 |
| - const css = rule.loaders.find((loader) => loader.loader === "css-loader"); |
45 |
| - |
46 |
| - if (css != undefined) { |
47 |
| - if (this.oneOf) { |
48 |
| - const postCssConfig = rule.loaders.find( |
49 |
| - (loader) => loader.loader === "postcss-loader" |
50 |
| - ); |
51 |
| - |
52 |
| - delete rule.loaders; |
53 |
| - Object.assign(rule, { |
54 |
| - test: /\.css$/, |
55 |
| - oneOf: [ |
56 |
| - { |
57 |
| - resourceQuery: /module/, |
58 |
| - use: [ |
59 |
| - "style-loader", |
60 |
| - { |
61 |
| - loader: "css-loader", |
62 |
| - options: this[this.mode](), |
63 |
| - }, |
64 |
| - ], |
65 |
| - }, |
66 |
| - { |
67 |
| - use: ["style-loader", postCssConfig], |
68 |
| - }, |
69 |
| - ], |
70 |
| - }); |
71 |
| - } else { |
72 |
| - Object.assign(css.options, this[this.mode]()); |
73 |
| - } |
74 |
| - } |
75 | 64 |
|
76 |
| - if ( |
77 |
| - this.sass && |
78 |
| - sass != undefined && |
79 |
| - rule.test.toString() === /\.scss$/.toString() |
80 |
| - ) { |
81 |
| - const postCssLoader = rule.loaders.find( |
82 |
| - (l) => l.loader === "postcss-loader" |
83 |
| - ); |
84 |
| - const sassLoader = rule.loaders.find((l) => l.loader === "sass-loader"); |
85 |
| - delete rule.loaders; |
86 |
| - |
87 |
| - Object.assign(rule, { |
88 |
| - test: /\.scss$/, |
89 |
| - use: [ |
90 |
| - "style-loader", |
91 |
| - { |
92 |
| - loader: "css-loader", |
93 |
| - options: this[this.mode](), |
94 |
| - }, |
95 |
| - postCssLoader, |
96 |
| - sassLoader, |
97 |
| - ], |
| 65 | + if (this.options.oneOf) this.handleOneOfPreProcessor(sassLoaders); |
| 66 | + else this.handlePreProcessor(sassLoaders); |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * handle normal css-module |
| 72 | + * |
| 73 | + * @param {*} cssLoaders |
| 74 | + * @returns |
| 75 | + * @memberof VueCssModule |
| 76 | + * |
| 77 | + */ |
| 78 | + handleCss(cssLoaders) { |
| 79 | + this.handleExclude(cssLoaders); |
| 80 | + |
| 81 | + cssLoaders.loaders.forEach((cssLoader) => { |
| 82 | + if (cssLoader.loader === "css-loader") { |
| 83 | + Object.assign(cssLoader, { |
| 84 | + options: this.options.cssLoaderOptions, |
98 | 85 | });
|
99 | 86 | }
|
100 |
| - |
101 |
| - return rule; |
102 | 87 | });
|
103 | 88 |
|
104 |
| - return webpackConfig; |
| 89 | + return cssLoaders; |
105 | 90 | }
|
106 | 91 |
|
107 | 92 | /**
|
108 |
| - * Return default mode |
| 93 | + * handle oneOf css-module |
109 | 94 | *
|
110 |
| - * @return {object} |
| 95 | + * @param {*} cssLoaders |
| 96 | + * @returns |
| 97 | + * @memberof VueCssModule |
111 | 98 | */
|
112 |
| - global() { |
113 |
| - return { |
114 |
| - modules: true, |
115 |
| - localIdentName: this.localIdentName, |
116 |
| - }; |
| 99 | + handleOneOfCss(cssLoaders) { |
| 100 | + this.handleExclude(cssLoaders); |
| 101 | + |
| 102 | + // keep default config for postcss-loader |
| 103 | + const postCssLoader = cssLoaders.loaders.find( |
| 104 | + (cssLoader) => cssLoader.loader === "postcss-loader" |
| 105 | + ); |
| 106 | + |
| 107 | + // reset loaders change with use |
| 108 | + delete cssLoaders.loaders; |
| 109 | + |
| 110 | + cssLoaders.oneOf = [ |
| 111 | + { |
| 112 | + resourceQuery: /module/, |
| 113 | + use: [ |
| 114 | + "style-loader", |
| 115 | + { |
| 116 | + loader: "css-loader", |
| 117 | + options: this.options.cssLoaderOptions, |
| 118 | + }, |
| 119 | + ], |
| 120 | + }, |
| 121 | + { |
| 122 | + use: ["style-loader", postCssLoader], |
| 123 | + }, |
| 124 | + ]; |
| 125 | + |
| 126 | + return cssLoaders; |
117 | 127 | }
|
118 | 128 |
|
119 | 129 | /**
|
120 |
| - * Return local mode |
| 130 | + * handle normal css-module for pre-processcor |
121 | 131 | *
|
122 |
| - * @return {object} |
| 132 | + * @param {*} sassLoaders |
| 133 | + * @returns |
| 134 | + * @memberof VueCssModule |
123 | 135 | */
|
124 |
| - local() { |
125 |
| - return { |
126 |
| - modules: { |
127 |
| - mode: this.mode, |
128 |
| - localIdentName: this.localIdentName, |
| 136 | + handlePreProcessor(sassLoaders) { |
| 137 | + this.handleExclude(sassLoaders); |
| 138 | + |
| 139 | + const [postCssLoader, sassLoader] = this.getDefaultPreProcessorConfig( |
| 140 | + sassLoaders |
| 141 | + ); |
| 142 | + |
| 143 | + // re-create config & add custom css-loader for .scss |
| 144 | + sassLoaders.loaders = [ |
| 145 | + "style-loader", |
| 146 | + { |
| 147 | + loader: "css-loader", |
| 148 | + options: this.options.cssLoaderOptions, |
129 | 149 | },
|
130 |
| - }; |
| 150 | + postCssLoader, |
| 151 | + sassLoader, |
| 152 | + ]; |
| 153 | + |
| 154 | + return sassLoaders; |
| 155 | + } |
| 156 | + |
| 157 | + /** |
| 158 | + * handle oneOf css-module for pre-processcor |
| 159 | + * |
| 160 | + * @param {*} sassLoaders |
| 161 | + * @returns |
| 162 | + * @memberof VueCssModule |
| 163 | + */ |
| 164 | + handleOneOfPreProcessor(sassLoaders) { |
| 165 | + this.handleExclude(sassLoaders); |
| 166 | + |
| 167 | + const [postCssLoader, sassLoader] = this.getDefaultPreProcessorConfig( |
| 168 | + sassLoaders |
| 169 | + ); |
| 170 | + |
| 171 | + delete sassLoaders.loaders; |
| 172 | + |
| 173 | + sassLoaders.oneOf = [ |
| 174 | + { |
| 175 | + resourceQuery: /module/, |
| 176 | + use: [ |
| 177 | + "style-loader", |
| 178 | + { |
| 179 | + loader: "css-loader", |
| 180 | + options: this.options.cssLoaderOptions, |
| 181 | + }, |
| 182 | + ], |
| 183 | + }, |
| 184 | + { |
| 185 | + use: ["style-loader", "css-loader", postCssLoader, sassLoader], |
| 186 | + }, |
| 187 | + ]; |
| 188 | + |
| 189 | + return sassLoaders; |
| 190 | + } |
| 191 | + |
| 192 | + /** |
| 193 | + * get default config from laravel-mix |
| 194 | + * |
| 195 | + * @param {*} sassLoaders |
| 196 | + * @returns |
| 197 | + * @memberof VueCssModule |
| 198 | + */ |
| 199 | + getDefaultPreProcessorConfig(sassLoaders) { |
| 200 | + // keep default config for postcss-loader |
| 201 | + const postCssLoader = sassLoaders.loaders.find( |
| 202 | + (sassLoader) => sassLoader.loader === "postcss-loader" |
| 203 | + ); |
| 204 | + |
| 205 | + // keep default config for sass-loader |
| 206 | + const sassLoader = sassLoaders.loaders.find( |
| 207 | + (sassLoader) => sassLoader.loader === "sass-loader" |
| 208 | + ); |
| 209 | + |
| 210 | + return [postCssLoader, sassLoader]; |
| 211 | + } |
| 212 | + |
| 213 | + /** |
| 214 | + * handle exclude |
| 215 | + * |
| 216 | + * @param {*} loaders |
| 217 | + * @returns |
| 218 | + * @memberof VueCssModule |
| 219 | + */ |
| 220 | + handleExclude(loaders) { |
| 221 | + if (this.options.exclude.length > 0) { |
| 222 | + if (loaders.exclude === undefined) { |
| 223 | + loaders.exclude = this.options.exclude; |
| 224 | + } else { |
| 225 | + this.options.exclude.forEach((e) => loaders.exclude.push(e)); |
| 226 | + } |
| 227 | + } |
| 228 | + |
| 229 | + return loaders; |
| 230 | + } |
| 231 | + |
| 232 | + /** |
| 233 | + * get default type for localIdentName |
| 234 | + * |
| 235 | + * @returns |
| 236 | + * @memberof VueCssModule |
| 237 | + */ |
| 238 | + defaultLocalIdentName(type) { |
| 239 | + if (type === "react") { |
| 240 | + return this.reactLocalIdentName(); |
| 241 | + } |
| 242 | + |
| 243 | + if (type === "discord") { |
| 244 | + return this.discordLocalIdentName(); |
| 245 | + } |
| 246 | + |
| 247 | + return Mix.inProduction() ? "[hash:base64]" : "[path][name]__[local]"; |
| 248 | + } |
| 249 | + |
| 250 | + /** |
| 251 | + * Example localIdentName like react |
| 252 | + */ |
| 253 | + reactLocalIdentName() { |
| 254 | + return "[name]___[local]___[hash:base64:5]"; |
| 255 | + } |
| 256 | + |
| 257 | + /** |
| 258 | + * Example localIdentName like discord |
| 259 | + */ |
| 260 | + discordLocalIdentName() { |
| 261 | + return "[local]-[hash:base64:5]"; |
131 | 262 | }
|
132 | 263 | }
|
133 | 264 |
|
134 |
| -mix.extend("vueCssModules", new VueCssModule()); |
| 265 | +mix.extend("vueCssModules", new VueCssModules()); |
0 commit comments