Skip to content

Instantly share code, notes, and snippets.

@artem-malko
Last active November 18, 2019 09:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save artem-malko/5446a112f706f9eedf7211d6ad6a05bf to your computer and use it in GitHub Desktop.
Save artem-malko/5446a112f706f9eedf7211d6ad6a05bf to your computer and use it in GitHub Desktop.
css-in-js-loader.ts
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