import fs from "fs" import { extname } from "path" import * as babel from "@babel/core" import type * as esbuild from "esbuild" import { fileName } from "./babel-filename" import { dynamicImport } from "./babel-dynamic-import" import { inlineCSSVariables } from "./babel-inline-css-vars" import { componentName } from "./babel-component-name" // import { whyDidYouRender } from "./babel-why-did-you-render"; // import constantElement from "./babel-constant-element"; const __PROD__ = process.env.NODE_ENV === "production" export type BabelPlugin = ( Babel: typeof babel, ) => babel.PluginObj export interface BabelPluginData { path: string } export const babelPlugin = (extraPlugins: babel.PluginItem[] = []): esbuild.Plugin => ({ name: "babel", setup(build) { function* getBabelPlugins( path: string, content: string, ): Generator { const hasFileName = content.includes("__filename") const hasDirName = content.includes("__dirname") if (hasFileName || hasDirName) { yield fileName({ hasFileName, hasDirName, path }) } if (!__PROD__ && /<\w/.test(content)) { yield componentName() } // if (!__PROD__ && content.includes("use")) { // yield whyDidYouRender({ // hookName: "useWhyDidYouUpdate", // hookPath: resolve(__dirname, "../../src/shared/hooks/useWhy.ts"), // ignoredHooks: ["useTreeContext"], // }); // } if (content.includes("vars.") || content.includes("token.")) { yield inlineCSSVariables() } if (content.includes("await import(`")) { yield dynamicImport(path) } if (content.includes('.macro"') || content.includes("/macro")) { yield ["babel-plugin-macros", { typeGraphQL: { useParameterDecorator: true } }] } if (content.includes("@emotion")) { yield [require("@emotion/babel-plugin"), { sourceMap: false }] } if (__PROD__ && content.includes("gql`")) { yield [require("babel-plugin-transform-minify-gql-template-literals")] } } build.onLoad({ filter: /\.tsx?$/ }, args => { if (args.path.includes("node_modules/")) { return null } const { path } = args const file = fs.readFileSync(path, "utf-8") const plugins: babel.PluginItem[] = Array.from(getBabelPlugins(path, file)).concat( extraPlugins, ) let code = file const pluginData: BabelPluginData = { path } if (plugins.length) { const res = babel.transformSync(file, { filename: path, babelrc: false, configFile: false, parserOpts: { plugins: ["typescript", "decorators-legacy", "jsx", "importAssertions"], }, generatorOpts: { decoratorsBeforeExport: true }, plugins, })! code = res.code! } else { return null } return { contents: code, loader: extname(path).slice(1) as any, pluginData, } }) }, })