Created
January 11, 2023 08:42
-
-
Save sachin-hg/4b96dbc20d673b93288d595527fc1a81 to your computer and use it in GitHub Desktop.
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
const parser = require('@babel/parser') | |
const { default: traverse } = require('@babel/traverse') | |
const { plugin1, plugin2 } = require('./find-cx-babel-plugin') | |
const t = require('@babel/types') | |
const cx = require('./cx.cjs') | |
const { default: generate } = require('@babel/generator') | |
const parse = (code, traverser) => { | |
let ast = parser.parse(code, { | |
sourceType: 'module', | |
plugins: ['jsx'] | |
}) | |
traverse(ast, traverser) | |
return ast | |
} | |
const modify = (nodes, moduleData, variables, programPath, moduleVsImport) => { | |
for (let path of nodes) { | |
const classNames = path.node.arguments.map(arg => { | |
if (arg.type === 'Identifier') { | |
const { module, importedAs } = variables[arg.name] | |
const map = moduleData[module] | |
const value = map[importedAs] | |
return value | |
} | |
return arg.value | |
}) | |
path.replaceWith(t.stringLiteral(cx(...classNames))) | |
} | |
const variableNames = Object.values(moduleVsImport) | |
if (variableNames.length) { | |
// this is required for the following use case | |
/* | |
import {x} from './style' | |
import {y} from './style2' | |
import {cx} from '@linaria/core' | |
export default () => <div className={cx(x, y)} /> | |
*/ | |
// in the above example after the cx function is called at build time | |
// the imports x,y become unused | |
// which causes ./style and ./style2 to be tree shaken | |
// this is a problem because these files have the actual import for css files created by linaria | |
// therefore this hack makes these imports useful by creating a sideeffect like so: | |
/* | |
import __atomic_style_handler__ from 'atomic-style-handler/dummyFunctionImport' | |
__atomic_style_handler__(x, y) | |
*/ | |
const vars = variableNames.map(variableName => t.identifier(variableName)) | |
programPath.node.body.splice( | |
0, | |
0, | |
t.importDeclaration( | |
[t.importDefaultSpecifier(t.identifier('__atomic_style_handler__'))], | |
t.stringLiteral('atomic-style-handler/dummyFunctionImport') | |
) | |
) | |
programPath.node.body.push( | |
t.expressionStatement( | |
t.callExpression(t.identifier('__atomic_style_handler__'), vars) | |
) | |
) | |
} | |
} | |
module.exports = function (source, sourceMap, meta) { | |
const callback = this.async() | |
const _this = this | |
let state = { variables: {}, modules: [], nodes: [], moduleVsImport: {} } | |
const ast = parse(source.toString(), plugin1(state)) | |
const moduleData = {} | |
if (state.modules.length) { | |
Promise.all( | |
state.modules.map(module => { | |
return new Promise((res, rej) => { | |
const map = {} | |
moduleData[module] = map | |
_this.loadModule(module, function (err, source) { | |
if (err) { | |
rej(err) | |
return | |
} | |
parse(source, plugin2(map)) | |
res() | |
}) | |
}) | |
}) | |
) | |
.then(() => { | |
modify( | |
state.nodes, | |
moduleData, | |
state.variables, | |
state.programPath, | |
state.moduleVsImport | |
) | |
callback(null, generate(ast).code, sourceMap, meta) | |
}) | |
.catch(e => callback(e)) | |
return | |
} | |
callback(null, source, sourceMap, meta) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment