UNPKG

stylex-webpack

Version:

The another Webpack Plugin for Facebook's StyleX

75 lines (69 loc) 3.43 kB
'use strict'; 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;