Skip to content

Instantly share code, notes, and snippets.

@JonatasAmaral
Last active February 27, 2022 22:43
Show Gist options
  • Save JonatasAmaral/ca1e3d667215a8febc219b3e97277a79 to your computer and use it in GitHub Desktop.
Save JonatasAmaral/ca1e3d667215a8febc219b3e97277a79 to your computer and use it in GitHub Desktop.
/**
* @file Script de alteração dos loaders do laravel-mix, para importar cssModules apenas nos arquivos pertinentes
* adaptado do pacote [laravel-mix-react-css-modules](https://www.npmjs.com/package/laravel-mix-react-css-modules)
*
* @author Jonatas Amaral
*/
const mix = require("laravel-mix");
/**
* Makes a full copy of an Array/Object
*
* @template ToClone
* @param { ToClone } items
* @return { ToClone }
*/
function deepClone(items) {
if (Array.isArray(items)) {
return items.map(item => deepClone(item))
}
if (items instanceof RegExp) return items
if (typeof items === 'object' && items !== null) {
let copyObj = {}
for (let k in items) {
copyObj[k] = deepClone(items[k])
}
return copyObj
}
return items
}
/**
* Concatenate two regular expressions
* [credits](https://masteringjs.io/tutorials/fundamentals/concat-regexp)
* @param {RegExp} reg
* @param {RegExp} exp
* @returns RegExp
*/
function concatRegexp(reg, exp) {
let flags = reg.flags + exp.flags;
flags = Array.from(new Set(flags.split(''))).join();
return new RegExp(reg.source + exp.source, flags);
}
class ImportCssModules {
static name = "cssModules";
constructor() {
// default configurations
// className pattern if not set on usage
this.classNamePattern = "[path]__[local]___[id]-[hash:base64:8]";
// enable sourceMaps by default
this.sourceMap = true
}
register(args = {}) {
// optional configuration parameters
const { classNamePattern, sourceMap } = args;
if (classNamePattern) {
this.classNamePattern = classNamePattern;
}
if (sourceMap) {
this.sourceMap = sourceMap;
}
}
webpackConfig(config) {
config.module.rules = config.module.rules.map(rule => {
/**
* If it's a styles rule
* (has `css-modules` in the loaders array)
* */
if (Array.isArray(rule.loaders) && (
rule.loaders.some(
loader => loader === "css-loader" ||
loader.loader === "css-loader"
)
)) {
// does a deep clone of rules, and turns it into cssModules rules
let cssModulesLoader = deepClone(rule.loaders).map(loader => {
// if it is a string css-loader, turns it into an objet
if (loader === "css-loader" || loader === "sass-loader") {
loader = { loader, options: {} }
}
// if it's an 'css-loader' object
if (loader.loader === "css-loader") {
loader.options.modules = true
loader.options.localIdentName = this.classNamePattern
loader.options.sourceMap = this.sourceMap
loader.options.url = true // enables aliases solving
}
// if it's not css-loader, does nothing
return loader;
});
// use oneOf, on following order
// 1 .module.css | .modules.css
// 2 .css?module | .css?modules
// 3 .css
return {
oneOf: [
{
...rule,
loaders: cssModulesLoader,
test: concatRegexp(/\.modules?/, RegExp(rule.test)) // garante que o test é um RegExp
},
{ ...rule, loaders: cssModulesLoader, resourceQuery: /modules?/ },
rule
]
}
}
// if it's not a loader rule, does nothing
return rule;
})
}
}
mix.extend(ImportCssModules.name, new ImportCssModules());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment