├── .github └── dependabot.yml ├── LICENSE ├── README.md ├── index.js └── package.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "22:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Aslam H 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Working with vue & css module is USELESS at least for me, please don't use css module it's only wasting your time!. 3 |

4 |

5 | Laravel Mix Vue Css Modules 6 |
7 | npm npm 8 |

9 | 10 | Add support for css module laravel mix. 11 | 12 | ## Installation 13 | 14 | ``` 15 | npm i laravel-mix-vue-css-modules --save-dev 16 | ``` 17 | 18 | ## Recommended v3 19 | 20 | [Example](https://github.com/Aslam97/laravel-mix-vue-css-modules/tree/v3#example) 21 | 22 | |Laravel Mix|Laravel Mix Vue CSS Modules|Pre-Processor|Install command| 23 | |---|---|---|---| 24 | |v5|v2|SCSS|`npm install laravel-mix-vue-css-modules@2`| 25 | |v5|[v3](https://github.com/Aslam97/laravel-mix-vue-css-modules/tree/v3)|SCSS, LESS, STYLUS|`npm install laravel-mix-vue-css-modules@3`| 26 | 27 | ## Usage 28 | 29 | First, VueCssModules must be enabled. Your `webpack.mix.js` could look like this: 30 | 31 | ```js 32 | const mix = require("laravel-mix"); 33 | require("laravel-mix-vue-css-modules"); 34 | 35 | mix.vueCssModules(); 36 | ``` 37 | 38 | Then, add the module attribute to your ` 49 | ``` 50 | 51 | You can then use it in your templates with a dynamic class binding: 52 | 53 | ```vue 54 | 57 | ``` 58 | 59 | And that's it. you ready to go. 60 | 61 | #### Opt-in Usage 62 | 63 | If you only want to use CSS Modules in some of your Vue components, you can set `oneOf` to `true` 64 | 65 | ```js 66 | mix.vueCssModules({ oneOf: true }); 67 | ``` 68 | 69 | #### Pre-Processors 70 | 71 | CSS Modules can be used along with other pre-processors. default pre-processor is enable. to disable it set `preProcessor` to `false` 72 | 73 | ```js 74 | mix.vueCssModules({ preProcessor: false }); 75 | ``` 76 | 77 | #### Custom localIdentName 78 | 79 | Default: 80 | 81 | - `[path][name]__[local]` for development 82 | - `[hash:base64]` for production 83 | 84 | ```js 85 | mix.vueCssModules({ 86 | cssLoaderOptions: { localIdentName: "[path][name]__[local]" }, 87 | }); 88 | ``` 89 | 90 | or you can use **react** or **discord** localIdentName 91 | 92 | ```js 93 | mix.vueCssModules({ localIdentNameType: "react" }); 94 | ``` 95 | 96 | #### Enable sourceMap 97 | 98 | Default: `false` 99 | 100 | ```js 101 | mix.vueCssModules({ cssLoaderOptions: { sourceMap: true } }); 102 | ``` 103 | 104 | #### Set importLoaders 105 | 106 | Default: `1` 107 | 108 | ```js 109 | mix.vueCssModules({ cssLoaderOptions: { importLoaders: 2 } }); 110 | ``` 111 | 112 | #### Exclude css 113 | 114 | you may want some of your css exluded from generated class by css module. 115 | 116 | ```js 117 | const getLocalIdent = require("css-loader/lib/getLocalIdent"); 118 | 119 | mix.vueCssModules({ 120 | cssLoaderOptions: { 121 | getLocalIdent: (context, localIdentName, localName, options) => { 122 | return context.resourcePath.includes("x.scss") 123 | ? localName 124 | : getLocalIdent(context, localIdentName, localName, options); 125 | }, 126 | }, 127 | }); 128 | ``` 129 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const mix = require("laravel-mix"); 2 | 3 | class VueCssModules { 4 | /** 5 | * Register the component. 6 | * 7 | * @param {Object} options 8 | * @param {Boolean} [options.oneOf] 9 | * @param {Boolean} [options.preProcessor] 10 | * @param {String} [options.localIdentNameType] 11 | * @param {Object} [options.cssLoaderOptions] 12 | */ 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: 20 | options.cssLoaderOptions && options.cssLoaderOptions.localIdentName 21 | ? options.cssLoaderOptions.localIdentName 22 | : this.defaultLocalIdentName(options.localIdentNameType), // {String} 23 | }; 24 | 25 | const cssLoaderOptions = { 26 | ...config, 27 | ...options.cssLoaderOptions, 28 | }; 29 | 30 | delete options.cssLoaderOptions; 31 | 32 | this.options = Object.assign( 33 | { 34 | oneOf: false, 35 | preProcessor: true, 36 | exclude: [], 37 | cssLoaderOptions: cssLoaderOptions, 38 | }, 39 | options 40 | ); 41 | } 42 | 43 | /** 44 | * Override the generated webpack configuration. 45 | * 46 | * @param {Object} config 47 | */ 48 | webpackConfig(config) { 49 | // for css-loader 50 | const cssLoaders = config.module.rules.find( 51 | (rule) => rule.test.toString() === "/\\.css$/" 52 | ); 53 | 54 | if (this.options.oneOf) this.handleOneOfCss(cssLoaders); 55 | else this.handleCss(cssLoaders); 56 | 57 | // only if pre-processor activated || default is active 58 | if (this.options.preProcessor) { 59 | // for sass-loader 60 | const sassLoaders = config.module.rules.find( 61 | (rule) => rule.test.toString() === "/\\.scss$/" 62 | ); 63 | 64 | if (this.options.oneOf) this.handleOneOfPreProcessor(sassLoaders); 65 | else this.handlePreProcessor(sassLoaders); 66 | } 67 | } 68 | 69 | /** 70 | * handle normal css-module 71 | * 72 | * @param {*} cssLoaders 73 | * @returns 74 | * @memberof VueCssModule 75 | * 76 | */ 77 | handleCss(cssLoaders) { 78 | this.handleExclude(cssLoaders); 79 | 80 | cssLoaders.loaders.forEach((cssLoader) => { 81 | if (cssLoader.loader === "css-loader") { 82 | Object.assign(cssLoader, { 83 | options: this.options.cssLoaderOptions, 84 | }); 85 | } 86 | }); 87 | 88 | return cssLoaders; 89 | } 90 | 91 | /** 92 | * handle oneOf css-module 93 | * 94 | * @param {*} cssLoaders 95 | * @returns 96 | * @memberof VueCssModule 97 | */ 98 | handleOneOfCss(cssLoaders) { 99 | this.handleExclude(cssLoaders); 100 | 101 | // keep default config for postcss-loader 102 | const postCssLoader = cssLoaders.loaders.find( 103 | (cssLoader) => cssLoader.loader === "postcss-loader" 104 | ); 105 | 106 | // reset loaders change with use 107 | delete cssLoaders.loaders; 108 | 109 | cssLoaders.oneOf = [ 110 | { 111 | resourceQuery: /module/, 112 | use: [ 113 | "style-loader", 114 | { 115 | loader: "css-loader", 116 | options: this.options.cssLoaderOptions, 117 | }, 118 | ], 119 | }, 120 | { 121 | use: ["style-loader", "css-loader", postCssLoader], 122 | }, 123 | ]; 124 | 125 | return cssLoaders; 126 | } 127 | 128 | /** 129 | * handle normal css-module for pre-processcor 130 | * 131 | * @param {*} sassLoaders 132 | * @returns 133 | * @memberof VueCssModule 134 | */ 135 | handlePreProcessor(sassLoaders) { 136 | this.handleExclude(sassLoaders); 137 | 138 | const [postCssLoader, sassLoader] = this.getDefaultPreProcessorConfig( 139 | sassLoaders 140 | ); 141 | 142 | // re-create config & add custom css-loader for .scss 143 | sassLoaders.loaders = [ 144 | "style-loader", 145 | { 146 | loader: "css-loader", 147 | options: this.options.cssLoaderOptions, 148 | }, 149 | postCssLoader, 150 | sassLoader, 151 | ]; 152 | 153 | return sassLoaders; 154 | } 155 | 156 | /** 157 | * handle oneOf css-module for pre-processcor 158 | * 159 | * @param {*} sassLoaders 160 | * @returns 161 | * @memberof VueCssModule 162 | */ 163 | handleOneOfPreProcessor(sassLoaders) { 164 | this.handleExclude(sassLoaders); 165 | 166 | const [postCssLoader, sassLoader] = this.getDefaultPreProcessorConfig( 167 | sassLoaders 168 | ); 169 | 170 | delete sassLoaders.loaders; 171 | 172 | sassLoaders.oneOf = [ 173 | { 174 | resourceQuery: /module/, 175 | use: [ 176 | "style-loader", 177 | { 178 | loader: "css-loader", 179 | options: this.options.cssLoaderOptions, 180 | }, 181 | postCssLoader, 182 | sassLoader, 183 | ], 184 | }, 185 | { 186 | use: ["style-loader", "css-loader", postCssLoader, sassLoader], 187 | }, 188 | ]; 189 | 190 | return sassLoaders; 191 | } 192 | 193 | /** 194 | * get default config from laravel-mix 195 | * 196 | * @param {*} sassLoaders 197 | * @returns 198 | * @memberof VueCssModule 199 | */ 200 | getDefaultPreProcessorConfig(sassLoaders) { 201 | // keep default config for postcss-loader 202 | const postCssLoader = sassLoaders.loaders.find( 203 | (sassLoader) => sassLoader.loader === "postcss-loader" 204 | ); 205 | 206 | // keep default config for sass-loader 207 | const sassLoader = sassLoaders.loaders.find( 208 | (sassLoader) => sassLoader.loader === "sass-loader" 209 | ); 210 | 211 | return [postCssLoader, sassLoader]; 212 | } 213 | 214 | /** 215 | * handle exclude 216 | * 217 | * @param {*} loaders 218 | * @returns 219 | * @memberof VueCssModule 220 | */ 221 | handleExclude(loaders) { 222 | if (this.options.exclude.length > 0) { 223 | if (loaders.exclude === undefined) { 224 | loaders.exclude = this.options.exclude; 225 | } else { 226 | this.options.exclude.forEach((e) => loaders.exclude.push(e)); 227 | } 228 | } 229 | 230 | return loaders; 231 | } 232 | 233 | /** 234 | * get default type for localIdentName 235 | * 236 | * @returns 237 | * @memberof VueCssModule 238 | */ 239 | defaultLocalIdentName(type) { 240 | if (type === "react") { 241 | return this.reactLocalIdentName(); 242 | } 243 | 244 | if (type === "discord") { 245 | return this.discordLocalIdentName(); 246 | } 247 | 248 | return Mix.inProduction() ? "[hash:base64]" : "[path][name]__[local]"; 249 | } 250 | 251 | /** 252 | * Example localIdentName like react 253 | */ 254 | reactLocalIdentName() { 255 | return "[name]___[local]___[hash:base64:5]"; 256 | } 257 | 258 | /** 259 | * Example localIdentName like discord 260 | */ 261 | discordLocalIdentName() { 262 | return "[local]-[hash:base64:5]"; 263 | } 264 | } 265 | 266 | mix.extend("vueCssModules", new VueCssModules()); 267 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-mix-vue-css-modules", 3 | "version": "2.1.3", 4 | "description": "A Laravel Mix extension for css modules support.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Aslam97/laravel-mix-vue-css-modules.git" 12 | }, 13 | "keywords": [ 14 | "laravel", 15 | "laravel-mix", 16 | "css-modules", 17 | "mix", 18 | "webpack", 19 | "vue-css-modules", 20 | "modules" 21 | ], 22 | "author": "Aslam", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/Aslam97/laravel-mix-vue-css-modules/issues" 26 | }, 27 | "homepage": "https://github.com/Aslam97/laravel-mix-vue-css-modules#readme", 28 | "peerDependencies": { 29 | "laravel-mix": "^5.0.1" 30 | } 31 | } 32 | --------------------------------------------------------------------------------