UNPKG

@dr.pogodin/babel-plugin-react-css-modules

Version:

Transforms styleName to className using compile time CSS module resolution.

131 lines (126 loc) 5.23 kB
/* global console, process */ // TODO: Flow-bin has issues with using "node:" prefix. // eslint-disable-next-line import/enforce-node-protocol-usage import { readFileSync } from 'fs'; // TODO: Flow-bin has issues with using "node:" prefix. // eslint-disable-next-line import/enforce-node-protocol-usage import { createRequire } from 'module'; // TODO: Flow-bin has issues with using "node:" prefix. // eslint-disable-next-line import/enforce-node-protocol-usage import { dirname, resolve } from 'path'; import postcss from 'postcss'; import ExtractImports from 'postcss-modules-extract-imports'; import LocalByDefault from 'postcss-modules-local-by-default'; import newScopePlugin from 'postcss-modules-scope'; import Values from 'postcss-modules-values'; import parser from '@dr.pogodin/postcss-modules-parser'; import getLocalIdent, { unescape } from "./getLocalIdent.js"; import optionsDefaults from "./schemas/optionsDefaults.js"; // $FlowFixMe const require = createRequire(import.meta.url); const getFiletypeOptions = (cssSourceFilePath, filetypes) => { const extension = cssSourceFilePath.slice(cssSourceFilePath.lastIndexOf('.')); const filetype = filetypes ? filetypes[extension] : null; return filetype; }; const getSyntax = filetypeOptions => { if (!filetypeOptions || !filetypeOptions.syntax) { return null; } // eslint-disable-next-line import/no-dynamic-require return require(filetypeOptions.syntax); }; const getExtraPlugins = filetypeOptions => { if (!filetypeOptions || !filetypeOptions.plugins) { return []; } return filetypeOptions.plugins.map(plugin => { if (Array.isArray(plugin)) { const [pluginName, pluginOptions] = plugin; // $FlowFixMe return require(pluginName)(pluginOptions); // eslint-disable-line import/no-dynamic-require } // eslint-disable-next-line import/no-dynamic-require return require(plugin); }); }; const getTokens = (extraPluginsRunner, runner, cssSourceFilePath, filetypeOptions, pluginOptions) => { const options = { from: cssSourceFilePath }; if (filetypeOptions) { options.syntax = getSyntax(filetypeOptions); } let res = readFileSync(cssSourceFilePath, 'utf-8'); if (pluginOptions.transform) { res = pluginOptions.transform(res, cssSourceFilePath, pluginOptions); } if (extraPluginsRunner) { res = extraPluginsRunner.process(res, options); } res = runner.process(res, options); res.warnings().forEach(message => { // eslint-disable-next-line no-console console.warn(message.text); }); return res.root.tokens; }; export default (cssSourceFilePath, options) => { // eslint-disable-next-line prefer-const let runner; let generateScopedName; if (options.generateScopedName && typeof options.generateScopedName === 'function') { ({ generateScopedName } = options); } else { generateScopedName = (clazz, resourcePath) => getLocalIdent( // TODO: The loader context used by "css-loader" may has additional // stuff inside this argument (loader context), allowing for some edge // cases (though, presumably not with a typical configurations) // we don't support (yet?). { resourcePath }, options.generateScopedName || optionsDefaults.generateScopedName, unescape(clazz), { clazz, context: options.context || process.cwd(), // TODO: These options should match their counterparts in Webpack // configuration: // - https://webpack.js.org/configuration/output/#outputhashdigest // - https://webpack.js.org/configuration/output/#outputhashdigestlength // - https://webpack.js.org/configuration/output/#outputhashfunction // - https://webpack.js.org/configuration/output/#outputhashsalt // and they should be exposed as babel-plugin-react-css-modules // options. However, for now they are just hardcoded equal to // the Webpack's default settings. hashDigest: 'hex', hashDigestLength: 20, hashFunction: 'md4', hashSalt: '', // TODO: This option was introduced by css-loader@6.6.0. // To keep getLocalIdent() in sync with css-loader implementation, // I updated the code there, but similar to the parameters above, // it is not yet exposed as this plugin's option. hashStrategy: 'resource-path-and-local-name', // TODO: This one allows for some path modifications during // the transform. Probably, not a Webpack param. regExp: '' }); } const filetypeOptions = getFiletypeOptions(cssSourceFilePath, options.filetypes); const extraPlugins = getExtraPlugins(filetypeOptions); const extraPluginsRunner = extraPlugins.length && postcss(extraPlugins); const fetch = (to, from) => { const fromDirectoryPath = dirname(from); const toPath = resolve(fromDirectoryPath, to); return getTokens(extraPluginsRunner, runner, toPath, filetypeOptions, options); }; const plugins = [Values, LocalByDefault, ExtractImports, newScopePlugin({ generateScopedName }), parser({ fetch })]; runner = postcss(plugins); return getTokens(extraPluginsRunner, runner, cssSourceFilePath, filetypeOptions, options); }; //# sourceMappingURL=requireCssModule.js.map