stylex-webpack
Version:
The another Webpack Plugin for Facebook's StyleX
75 lines (69 loc) • 3.43 kB
JavaScript
;
var core = require('@babel/core');
var stylexBabelPlugin = require('@stylexjs/babel-plugin');
var guard = require('foxts/guard');
var path = require('node:path');
const LOADER_TRANSFORMED_FLAG = '/* [stylex-webpack] stylex-loader transformed */';
require.resolve('./stylex.css');
const VIRTUAL_STYLEX_CSS_DUMMY_IMPORT_PATH = require.resolve('./stylex-virtual.css');
const BUILD_INFO_STYLEX_KEY = '~stylex_webpack_stylex_rules';
function stringifyRequest(loaderContext, request) {
return JSON.stringify(loaderContext.utils.contextify(loaderContext.context || loaderContext.rootContext, request));
}
const PLUGIN_NAME = 'stylex';
async function stylexLoader(inputCode, inputSourceMap) {
const callback = this.async();
// bail out early if already transformed
// for some reason, a module might be passed to stylex-loader more than once, happened with Next.js App Router
if (inputCode.includes(LOADER_TRANSFORMED_FLAG)) {
return callback(null, inputCode, inputSourceMap);
}
const { stylexImports, stylexOption } = this.getOptions();
// bail out early if the input doesn't contain stylex imports
if (!stylexImports.some((importName)=>inputCode.includes(importName))) {
return callback(null, inputCode, inputSourceMap);
}
try {
const { code, map, metadata } = await core.transformAsync(inputCode, {
babelrc: false,
inputSourceMap,
sourceFileName: this.resourcePath,
filename: this.resourcePath,
parserOpts: {
plugins: /\.tsx?$/.test(this.resourcePath) ? [
'typescript',
'jsx'
] : [
'jsx'
]
},
plugins: [
stylexBabelPlugin.withOptions(stylexOption)
]
});
const logger = this._compiler?.getInfrastructureLogger(PLUGIN_NAME);
// If metadata.stylex doesn't exist at all, we only need to return the transformed code
if (!metadata || !('stylex' in metadata) || metadata.stylex == null) {
logger?.debug(`No stylex styles generated from ${this.resourcePath}`);
return callback(null, code ?? undefined, map ?? undefined);
}
// this.stylexRules[filename] = metadata.stylex;
logger?.debug(`Read stylex styles from ${this.resourcePath}:`, metadata.stylex);
guard.nullthrow(this._module?.buildInfo, '[stylex-webpack] Expected "this._module.buildInfo" to be defined')[BUILD_INFO_STYLEX_KEY] = {
resourcePath: this.resourcePath,
stylexRules: metadata.stylex
};
// Add a dummy virtual import that will be picked up by virtual dummy import loader to add fake CSS to invalidate HMR
const from = path.relative(this.rootContext, this.resourcePath);
const urlParams = new URLSearchParams({
from,
stylex: JSON.stringify(metadata.stylex) // color: #fff is not url safe, let's get through JSON.stringify
});
const virtualCssRequest = stringifyRequest(this, `${VIRTUAL_STYLEX_CSS_DUMMY_IMPORT_PATH}?${urlParams.toString()}`);
const postfix = `\nimport ${virtualCssRequest};\n${LOADER_TRANSFORMED_FLAG}`;
return callback(null, code + postfix, map ?? undefined);
} catch (error) {
return callback(error);
}
}
module.exports = stylexLoader;