-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #105 from Rezact/add-config-and-builder-plugins
Add config and builder plugins
- Loading branch information
Showing
7 changed files
with
275 additions
and
10 deletions.
There are no files selected for viewing
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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { UserConfig } from "vite"; | ||
|
||
interface defOptions { | ||
routes?: any[]; | ||
options?: { | ||
useMdx?: boolean; | ||
}; | ||
} | ||
|
||
export declare const configRezact: (item: defOptions) => UserConfig; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { rezact } from "./vite-plugin.js"; | ||
import { rezact_mdx } from "./vite-mdx-plugin.js"; | ||
import remarkFrontmatter from "remark-frontmatter"; | ||
import remarkMdxFrontmatter from "remark-mdx-frontmatter"; | ||
import rehypeHighlight from "rehype-highlight"; | ||
import mdx from "@mdx-js/rollup"; | ||
import { addRoutesToInput, rezactBuild } from "./vite-build-plugin.js"; | ||
import { defineConfig } from "vite"; | ||
|
||
const config = defineConfig({ | ||
resolve: { | ||
alias: { | ||
src: "/src", | ||
rezact: "@rezact/rezact", | ||
}, | ||
}, | ||
build: { | ||
target: "esnext", | ||
modulePreload: { | ||
polyfill: false, | ||
}, | ||
rollupOptions: {}, | ||
}, | ||
esbuild: { | ||
jsxFactory: "xCreateElement", | ||
jsxFragment: "xFragment", | ||
}, | ||
plugins: [], | ||
}); | ||
|
||
export function configRezact({ routes, options }) { | ||
const useMdx = options?.useMdx ?? true; | ||
if (!config.plugins) config.plugins = []; | ||
|
||
if (useMdx) | ||
config.plugins.push( | ||
mdx({ | ||
pragma: "r.xCreateElement", | ||
pragmaFrag: "r.xFragment", | ||
jsxRuntime: "classic", | ||
pragmaImportSource: "@rezact/rezact/mdx", | ||
remarkPlugins: [ | ||
remarkFrontmatter, | ||
[remarkMdxFrontmatter, { name: "fm" }], | ||
], | ||
rehypePlugins: [rehypeHighlight], | ||
}) | ||
); | ||
|
||
config.plugins.push(rezact()); | ||
|
||
if (useMdx) config.plugins.push(rezact_mdx()); | ||
|
||
if (routes) { | ||
addRoutesToInput(routes, config); | ||
config.plugins.push(rezactBuild({ routes })); | ||
} | ||
|
||
return config; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { dirname, resolve } from "path"; | ||
import * as fs from "fs"; | ||
import { GlobalRegistrator } from "@happy-dom/global-registrator"; | ||
import { fileURLToPath } from "url"; | ||
|
||
const __filename = fileURLToPath(import.meta.url); | ||
const __dirname = dirname(__filename).replace( | ||
"/node_modules/@rezact/rezact", | ||
"" | ||
); | ||
|
||
export function writeToFileSync(filePath, content) { | ||
fs.mkdirSync(dirname(filePath), { recursive: true }); | ||
fs.writeFileSync(filePath, content); | ||
} | ||
|
||
export async function rezactRendered() { | ||
return new Promise((resolve) => { | ||
const renderedFunc = (e) => { | ||
document.removeEventListener("rezact-rendered", renderedFunc); | ||
resolve(e); | ||
}; | ||
|
||
document.addEventListener("rezact-rendered", renderedFunc); | ||
}); | ||
} | ||
|
||
export function addRoutesToInput(routes, config) { | ||
const isBuild = process.env.npm_lifecycle_event === "build"; | ||
|
||
let rollupInput = { main: resolve(__dirname, "index.html") }; | ||
if (isBuild) { | ||
const indexFilePath = resolve(__dirname, "index.html"); | ||
const _idxFileText = fs.readFileSync(indexFilePath, "utf-8"); | ||
|
||
const mappedRoutes = routes.map((route) => { | ||
const htmlFilePath = __dirname + route.path + ".html"; | ||
if (route.path !== "/" && !route.path.includes(":")) { | ||
let idxFileText = _idxFileText; | ||
writeToFileSync(htmlFilePath, idxFileText); | ||
rollupInput[route.path.replace(/\//g, "")] = resolve(htmlFilePath); | ||
} | ||
}); | ||
} | ||
|
||
config.build.rollupOptions.input = { ...rollupInput }; | ||
} | ||
|
||
function deleteFileAndEmptyDirs(filePath) { | ||
// Delete the file | ||
fs.unlinkSync(filePath); | ||
|
||
// Recursively remove parent directories if empty | ||
let dirPath = dirname(filePath); | ||
while (dirPath !== resolve(dirPath, "..")) { | ||
if (fs.readdirSync(dirPath).length === 0) { | ||
fs.rmdirSync(dirPath); | ||
dirPath = resolve(dirPath, ".."); | ||
} else { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
async function delay(ms) { | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
} | ||
|
||
// function findAllNestedImports(filePath) {} | ||
|
||
export function rezactBuild({ routes }) { | ||
return { | ||
name: "rezact-build", | ||
|
||
async writeBundle(options, bundle) { | ||
GlobalRegistrator.register({ | ||
url: `http://localhost:3000/`, | ||
}); | ||
const { happyDOM } = window; | ||
window.scrollTo = () => {}; | ||
document.body.innerHTML = `<div id="app"></div>`; | ||
|
||
let mainEntryJS = ""; | ||
const bundleMapped = {}; | ||
Object.keys(bundle).forEach((key) => { | ||
const path = bundle[key].facadeModuleId?.replace(/\.(tsx|jsx)$/, ""); | ||
if (path) bundleMapped[path] = bundle[key]; | ||
}); | ||
|
||
let mainModule = null; | ||
|
||
// convert this map into a for loop | ||
for (const route of routes) { | ||
console.log("rendering", route.path); | ||
const path = route.component.toString().split(/["'`]/)[1]; | ||
const resolvedPath = resolve(__dirname, path); | ||
const htmlFilePath = __dirname + route.path + ".html"; | ||
if (route.path !== "/" && !route.path.includes(":")) { | ||
deleteFileAndEmptyDirs(htmlFilePath); | ||
} | ||
|
||
const routeChunk = bundleMapped[resolvedPath]; | ||
const routePathMapName = (route.path.slice(1) || "index") + ".html"; | ||
let preloads = ""; | ||
const dedupePreload = {}; | ||
const preload = `<link rel="modulepreload" href="/${routeChunk.fileName}" />\n`; | ||
preloads += preload; | ||
routeChunk.imports.forEach((importPath) => { | ||
if (importPath.startsWith("assets/main-")) | ||
return (mainEntryJS = importPath); | ||
if (dedupePreload[importPath]) return; | ||
dedupePreload[importPath] = true; | ||
const preload = `<link rel="modulepreload" href="/${importPath}" />\n`; | ||
preloads += preload; | ||
}); | ||
|
||
const _modifiedSource = bundle[routePathMapName].source.replace( | ||
"<!-- PRELOAD HERE -->", | ||
preloads | ||
); | ||
|
||
if (mainModule === null) { | ||
const fullMainPath = __dirname + "/dist/" + mainEntryJS; | ||
mainModule = await import(fullMainPath); | ||
await rezactRendered(); | ||
} else { | ||
const anchor = document.createElement("a"); | ||
anchor.href = route.path; | ||
document.body.appendChild(anchor); | ||
anchor.click(); | ||
await rezactRendered(); | ||
await delay(100); | ||
} | ||
|
||
const app = document.getElementById("app"); | ||
const modifiedSource = _modifiedSource.replace( | ||
"<!-- PRE RENDER HERE -->", | ||
app.innerHTML | ||
); | ||
|
||
const outRoutePath = route.path === "/" ? "/index" : route.path; | ||
const outputHtmlFilePath = __dirname + "/dist" + outRoutePath + ".html"; | ||
|
||
writeToFileSync(outputHtmlFilePath, modifiedSource); | ||
} | ||
happyDOM.abort(); | ||
GlobalRegistrator.unregister(); | ||
// fs.writeFileSync("bundle.json", JSON.stringify(bundle, null, 2)); | ||
return; | ||
}, | ||
}; | ||
} |
Oops, something went wrong.