Last active
November 18, 2019 09:57
-
-
Save artem-malko/5446a112f706f9eedf7211d6ad6a05bf to your computer and use it in GitHub Desktop.
css-in-js-loader.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { loader } from 'webpack'; | |
import { storeInstance } from '../store'; | |
import { isValidStyleObject } from '../../generator/utils'; | |
const loaderUtils = require('loader-utils'); | |
// NodeJS Module | |
const Module = require('module'); | |
// Replacement for loader.exec | |
// https://github.com/webpack/webpack.js.org/issues/1268#issuecomment-313513988 | |
const exec = ( | |
loaderContext: loader.LoaderContext, | |
code: string, | |
filename: string, | |
// paths from resolve section in webpack config | |
additionalResolvePaths: string[], | |
) => { | |
const module = new Module(filename, loaderContext); | |
module.paths = Module._nodeModulePaths(loaderContext.context).concat(additionalResolvePaths); | |
module.filename = filename; | |
module._compile(code, filename); | |
delete require.cache[filename]; | |
return module.exports; | |
}; | |
interface LoaderParams { | |
resolveModules: string[]; | |
} | |
/** | |
* Default values for every param that can be passed in the loader query. | |
*/ | |
const DEFAULT_QUERY_VALUES: LoaderParams = { | |
resolveModules: [], | |
}; | |
// tslint:disable-next-line:only-arrow-functions | |
const loader: loader.Loader = function(source) { | |
const { resource } = this; | |
const callback = this.async(); | |
// Impossible situation | |
if (!callback) { | |
return; | |
} | |
// tslint:disable:no-null-keyword | |
if (!resource.includes('css.ts')) { | |
callback(null, source); | |
return; | |
} | |
// Parse the loader query and apply the default values in case no values are provided | |
const loaderParams: LoaderParams = Object.assign({}, DEFAULT_QUERY_VALUES, loaderUtils.getOptions(this)); | |
let executedModule: any = {}; | |
// Execute module with styles | |
try { | |
executedModule = exec(this, source.toString(), resource, loaderParams.resolveModules); | |
} catch (e) { | |
return callback(e); | |
} | |
const styleDescriptor = executedModule['styles']; | |
if (!styleDescriptor || !isValidStyleObject(styleDescriptor)) { | |
callback(null, source.toString()); | |
return; | |
} | |
const classNames = Object.keys(styleDescriptor); | |
const hashMap: { [key: string]: any } = {}; | |
classNames.forEach((className) => { | |
const { hash } = storeInstance.addStyles(className, styleDescriptor[className]); | |
hashMap[className] = hash; | |
}); | |
const result = `styles:${JSON.stringify(hashMap)}`; | |
// tslint:disable:no-null-keyword | |
callback(null, `module.exports={${result}}`); | |
}; | |
export default loader; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment