import { defineConfig, HtmlTagDescriptor } from 'vite'; import path from 'path'; import fs from 'fs'; import { nodePolyfills } from 'vite-plugin-node-polyfills'; import federation from '@originjs/vite-plugin-federation'; import reactBabel from '@vitejs/plugin-react'; const STATIC_CDN = 'https://landingbuilder-cdn.tekoapis.com'; const injectHtmlsServe: HtmlTagDescriptor[] = [ { tag: 'script', attrs: { src: '/env.js' }, injectTo: 'body' }, { tag: 'script', attrs: { src: '/host-mapping.js' }, injectTo: 'body' }, { tag: 'link', attrs: { rel: 'icon', href: '/favicon.png' }, injectTo: 'head-prepend', }, ]; const injectHtmlsBuild: HtmlTagDescriptor[] = [ ...injectHtmlsServe, { tag: 'script', attrs: { src: '/configs/env-local.js' }, injectTo: 'body' }, { tag: 'script', attrs: { src: '/configs/host-mapping.js' }, injectTo: 'body', }, { tag: 'script', attrs: { src: '/configs/ga.js', async: true }, injectTo: 'body', }, { tag: 'script', attrs: { src: '/configs/facebook.js', async: true }, injectTo: 'body', }, { tag: 'script', attrs: { src: '/configs/tracking-seo.js', async: true }, injectTo: 'body', }, ]; // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { // DEV - alias for package in workspace package packages/ const mappingDevMonorepoLibs = { '@tempi/3rd-components': 'packages/3rd-components/src', }; const sharedList = mode === 'production' ? [ '@tempi/core-editor', '@tempi/core-elements', '@tempi/core-renderer', '@tempi/editor-site', 'react', 'react-dom', '@emotion/styled', ] : ['react', 'react-dom']; const dirInSrc = fs .readdirSync('src', { withFileTypes: true }) .filter((dir) => dir.isDirectory()) .map((dir) => dir.name); const alias = dirInSrc.map((el) => { return { find: new RegExp(`^${el}(.*)`), replacement: path.join(path.resolve(__dirname, `src/${el}`), '$1'), }; }); return { server: { port: 3000, }, preview: { port: 3000, }, build: { assetsDir: 'static', outDir: 'build', target: 'esnext', }, base: mode === 'production' ? `${STATIC_CDN}/editor/` : '/', optimizeDeps: { include: ['react/jsx-runtime', 'react-dom', 'react', '@emotion/react'], }, plugins: [ // append link, script when serve (dev) { name: 'serve-html', apply: 'serve', transformIndexHtml: (html) => { return { html, tags: injectHtmlsServe, }; }, }, // append link, script when build { name: 'build-html', apply: 'build', transformIndexHtml: (html) => { return { html, tags: injectHtmlsBuild, }; }, }, nodePolyfills({ exclude: ['constants'], globals: { global: true, process: true, }, }), federation({ name: 'host-app', remotes: { dummy: 'dummy.js', customElement: { external: `Promise.resolve(new URLSearchParams(window.location.search)?.get('remoteUrl') || '')`, externalType: 'promise', }, }, shared: sharedList, }), /*** * Somehow reactBabel is not working in production mode * and somehow reactSwc is not working in local mode * So we need to use reactBabel in production and reactSwc in local * (っ °Д °;)っ (っ °Д °;)っ (っ °Д °;)っ */ reactBabel({ jsxImportSource: '@emotion/react', babel: { plugins: ['@emotion/babel-plugin'], }, }), , ], resolve: { alias: mode === 'production' ? [...alias] : [ ...Object.entries(mappingDevMonorepoLibs).map(([k, v]) => ({ find: k, replacement: path.resolve(__dirname, '../../', v), })), ...alias, ], }, }; });