Skip to content

Instantly share code, notes, and snippets.

@sachin-hg
Created January 11, 2023 08:42
Show Gist options
  • Save sachin-hg/4b96dbc20d673b93288d595527fc1a81 to your computer and use it in GitHub Desktop.
Save sachin-hg/4b96dbc20d673b93288d595527fc1a81 to your computer and use it in GitHub Desktop.
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