mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
split functions
This commit is contained in:
parent
645e088c1b
commit
4a2820597c
@ -1,173 +1,25 @@
|
||||
import { Widget } from "@models"
|
||||
|
||||
import { transform } from "sucrase"
|
||||
import UglifyJS from "uglify-js"
|
||||
|
||||
import path from "path"
|
||||
import resolveUrl from "@utils/resolveUrl"
|
||||
import replaceImportsWithRemoteURL from "@utils/replaceImportsWithRemoteURL"
|
||||
|
||||
async function compileWidgetCode(widgetCode, manifest, rootURL) {
|
||||
if (!widgetCode) {
|
||||
throw new Error("Widget code not defined.")
|
||||
}
|
||||
|
||||
if (!manifest) {
|
||||
throw new Error("Manifest not defined.")
|
||||
}
|
||||
|
||||
if (!rootURL) {
|
||||
throw new Error("Root URL not defined.")
|
||||
}
|
||||
|
||||
let renderComponentName = null
|
||||
let cssFiles = []
|
||||
|
||||
// inject react with cdn
|
||||
widgetCode = `import React from "https://cdn.skypack.dev/react@17?dts" \n${widgetCode}`
|
||||
|
||||
widgetCode = await replaceImportsWithRemoteURL(widgetCode, resolveUrl(rootURL, manifest.main))
|
||||
|
||||
// remove css imports and append to manifest (Only its used in the entry file)
|
||||
widgetCode = widgetCode.replace(/import\s+["'](.*)\.css["']/g, (match, p1) => {
|
||||
cssFiles.push(resolveUrl(rootURL, `${p1}.css`))
|
||||
|
||||
return ""
|
||||
})
|
||||
|
||||
// transform jsx to js
|
||||
widgetCode = await transform(widgetCode, {
|
||||
transforms: ["jsx"],
|
||||
//jsxRuntime: "automatic",
|
||||
//production: true,
|
||||
}).code
|
||||
|
||||
// search export default and get the name of the function/const/class
|
||||
const exportDefaultRegex = /export\s+default\s+(?:function|const|class)\s+([a-zA-Z0-9]+)/g
|
||||
|
||||
const exportDefaultMatch = exportDefaultRegex.exec(widgetCode)
|
||||
|
||||
if (exportDefaultMatch) {
|
||||
renderComponentName = exportDefaultMatch[1]
|
||||
}
|
||||
|
||||
// remove export default keywords
|
||||
widgetCode = widgetCode.replace("export default", "")
|
||||
|
||||
let manifestProcessed = {
|
||||
...manifest,
|
||||
}
|
||||
|
||||
manifestProcessed.cssFiles = cssFiles
|
||||
manifestProcessed.main = resolveUrl(rootURL, manifest.main)
|
||||
manifestProcessed.icon = resolveUrl(rootURL, manifest.icon)
|
||||
|
||||
let result = `
|
||||
${widgetCode}
|
||||
|
||||
export default {
|
||||
manifest: ${JSON.stringify(manifestProcessed)},
|
||||
renderComponent: ${renderComponentName},
|
||||
}
|
||||
`
|
||||
|
||||
// minify code
|
||||
result = UglifyJS.minify(result, {
|
||||
compress: true,
|
||||
mangle: true,
|
||||
}).code
|
||||
|
||||
return result
|
||||
}
|
||||
import getWidgetCode from "@utils/getWidgetCode"
|
||||
|
||||
export default async (req, res) => {
|
||||
const widgetId = req.params.widgetId
|
||||
|
||||
const useCache = req.query["use-cache"] ? toBoolean(req.query["use-cache"]) : true
|
||||
|
||||
// try to find Widget
|
||||
const widget = await Widget.findOne({
|
||||
_id: widgetId,
|
||||
}).catch(() => {
|
||||
return null
|
||||
const origin = `${toBoolean(process.env.FORCE_CODE_SSL) ? "https" : req.protocol}://${req.get("host")}`
|
||||
|
||||
let widgetCode = await getWidgetCode(widgetId, {
|
||||
useCache,
|
||||
origin,
|
||||
}).catch((error) => {
|
||||
res.status(500).json({
|
||||
error: error.message,
|
||||
})
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
if (!widget) {
|
||||
return res.status(404).json({
|
||||
error: "Widget not found.",
|
||||
})
|
||||
if (widgetCode) {
|
||||
res.setHeader("Content-Type", "application/javascript")
|
||||
return res.status(200).send(widgetCode)
|
||||
}
|
||||
|
||||
if (!widget.manifest.main) {
|
||||
return res.status(404).json({
|
||||
error: "Widget entry file not defined",
|
||||
})
|
||||
}
|
||||
|
||||
const requestedVersion = widgetId.split("@")[1] ?? widget.manifest.version
|
||||
|
||||
let widgetCode = null
|
||||
|
||||
// get origin from request url
|
||||
const origin = `${toBoolean(process.env.FORCE_CODE_SSL) ? "https" : req.protocol}://${req.get("host")}/static/widgets/${widgetId}@${requestedVersion}/`
|
||||
const remotePath = `/widgets/${widgetId}@${requestedVersion}/`
|
||||
|
||||
const remoteEntyFilePath = path.join(remotePath, widget.manifest.main)
|
||||
|
||||
if (useCache) {
|
||||
widgetCode = await global.redis.get(`${origin}:widget:${widgetId}@${requestedVersion}}`)
|
||||
}
|
||||
|
||||
if (!widgetCode) {
|
||||
try {
|
||||
widgetCode = await new Promise(async (resolve, reject) => {
|
||||
await global.storage.getObject(process.env.S3_BUCKET, remoteEntyFilePath, (error, dataStream) => {
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
|
||||
let data = ""
|
||||
|
||||
dataStream.on("data", (chunk) => {
|
||||
data += chunk
|
||||
})
|
||||
|
||||
dataStream.on("end", () => {
|
||||
resolve(data)
|
||||
})
|
||||
|
||||
dataStream.on("error", (error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
error: `Unable to get widget code from storage. ${error.message}`,
|
||||
requestedFile: remoteEntyFilePath
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`🔌 [widget:${widgetId}] Compiling widget code...`)
|
||||
|
||||
widgetCode = await compileWidgetCode(widgetCode, widget.manifest, origin)
|
||||
|
||||
await global.redis.set(`${origin}:widget:${widgetId}@${requestedVersion}}`, widgetCode)
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
message: "Unable to transform widget code.",
|
||||
error: error.message,
|
||||
})
|
||||
}
|
||||
|
||||
if (!widgetCode) {
|
||||
return res.status(404).json({
|
||||
error: "Widget not found.",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
res.setHeader("Content-Type", "application/javascript")
|
||||
return res.status(200).send(widgetCode)
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
import { Widget } from "@models"
|
||||
import getWidgetCode from "@utils/getWidgetCode"
|
||||
|
||||
export default async (req, res) => {
|
||||
const widget_id = req.params.widgetId
|
||||
|
||||
const widget = await Widget.findOne({
|
||||
_id: widget_id,
|
||||
}).catch(() => {
|
||||
return false
|
||||
})
|
||||
|
||||
if (!widget) {
|
||||
return res.status(404).json({
|
||||
error: "Widget not found",
|
||||
})
|
||||
}
|
||||
|
||||
const widgetCode = await getWidgetCode(widget_id, {
|
||||
useCache: false,
|
||||
origin: `${toBoolean(process.env.FORCE_CODE_SSL) ? "https" : req.protocol}://${req.get("host")}`,
|
||||
}).catch((error) => {
|
||||
res.status(500).json({
|
||||
error: error.message,
|
||||
})
|
||||
return false
|
||||
})
|
||||
|
||||
// create a development web preview using react app
|
||||
|
||||
return res.status(200).send(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Widget Preview</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<script>
|
||||
window.__debugState = {
|
||||
widgetCode: ${JSON.stringify(widgetCode)},
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/react/umd/react.development.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.development.js"></script>
|
||||
<script src="http://localhost:3040/static/devScripts/main.jsx"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Widget Preview</h2>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
import { transform } from "sucrase"
|
||||
import UglifyJS from "uglify-js"
|
||||
|
||||
import resolveUrl from "@utils/resolveUrl"
|
||||
import replaceImportsWithRemoteURL from "@utils/replaceImportsWithRemoteURL"
|
||||
|
||||
export default async (widgetCode, manifest, rootURL) => {
|
||||
if (!widgetCode) {
|
||||
throw new Error("Widget code not defined.")
|
||||
}
|
||||
|
||||
if (!manifest) {
|
||||
throw new Error("Manifest not defined.")
|
||||
}
|
||||
|
||||
if (!rootURL) {
|
||||
throw new Error("Root URL not defined.")
|
||||
}
|
||||
|
||||
let renderComponentName = null
|
||||
let cssFiles = []
|
||||
|
||||
// inject react with cdn
|
||||
widgetCode = `import React from "https://cdn.skypack.dev/react@17?dts" \n${widgetCode}`
|
||||
|
||||
widgetCode = await replaceImportsWithRemoteURL(widgetCode, resolveUrl(rootURL, manifest.main))
|
||||
|
||||
// remove css imports and append to manifest (Only its used in the entry file)
|
||||
widgetCode = widgetCode.replace(/import\s+["'](.*)\.css["']/g, (match, p1) => {
|
||||
cssFiles.push(resolveUrl(rootURL, `${p1}.css`))
|
||||
|
||||
return ""
|
||||
})
|
||||
|
||||
// transform jsx to js
|
||||
widgetCode = await transform(widgetCode, {
|
||||
transforms: ["jsx"],
|
||||
//jsxRuntime: "automatic",
|
||||
//production: true,
|
||||
}).code
|
||||
|
||||
// search export default and get the name of the function/const/class
|
||||
const exportDefaultRegex = /export\s+default\s+(?:function|const|class)\s+([a-zA-Z0-9]+)/g
|
||||
|
||||
const exportDefaultMatch = exportDefaultRegex.exec(widgetCode)
|
||||
|
||||
if (exportDefaultMatch) {
|
||||
renderComponentName = exportDefaultMatch[1]
|
||||
}
|
||||
|
||||
// remove export default keywords
|
||||
widgetCode = widgetCode.replace("export default", "")
|
||||
|
||||
let manifestProcessed = {
|
||||
...manifest,
|
||||
}
|
||||
|
||||
manifestProcessed.cssFiles = cssFiles
|
||||
manifestProcessed.main = resolveUrl(rootURL, manifest.main)
|
||||
manifestProcessed.icon = resolveUrl(rootURL, manifest.icon)
|
||||
|
||||
let result = `
|
||||
${widgetCode}
|
||||
|
||||
export default {
|
||||
manifest: ${JSON.stringify(manifestProcessed)},
|
||||
renderComponent: ${renderComponentName},
|
||||
}
|
||||
`
|
||||
|
||||
// minify code
|
||||
result = UglifyJS.minify(result, {
|
||||
compress: true,
|
||||
mangle: true,
|
||||
}).code
|
||||
|
||||
return result
|
||||
}
|
86
packages/marketplace_server/src/utils/getWidgetCode/index.js
Normal file
86
packages/marketplace_server/src/utils/getWidgetCode/index.js
Normal file
@ -0,0 +1,86 @@
|
||||
import { Widget } from "@models"
|
||||
import compileWidgetCode from "@utils/compileWidgetCode"
|
||||
import path from "path"
|
||||
|
||||
export default async (
|
||||
widgetId,
|
||||
{
|
||||
useCache = true,
|
||||
origin = null,
|
||||
}
|
||||
) => {
|
||||
if (!widgetId) {
|
||||
throw new Error("Widget ID not defined.")
|
||||
}
|
||||
if (!origin) {
|
||||
throw new Error("Origin not defined.")
|
||||
}
|
||||
|
||||
// try to find Widget
|
||||
const widget = await Widget.findOne({
|
||||
_id: widgetId,
|
||||
}).catch(() => {
|
||||
return null
|
||||
})
|
||||
|
||||
if (!widget) {
|
||||
throw new Error("Widget not found.")
|
||||
}
|
||||
|
||||
if (!widget.manifest.main) {
|
||||
throw new Error("Widget entry file not defined")
|
||||
}
|
||||
|
||||
const requestedVersion = widgetId.split("@")[1] ?? widget.manifest.version
|
||||
|
||||
let widgetCode = null
|
||||
|
||||
const finalOrigin = `${origin}/static/widgets/${widgetId}@${requestedVersion}/`
|
||||
const remotePath = `/widgets/${widgetId}@${requestedVersion}/`
|
||||
|
||||
const remoteEntyFilePath = path.join(remotePath, widget.manifest.main)
|
||||
|
||||
if (useCache) {
|
||||
widgetCode = await global.redis.get(`${origin}:widget:${widgetId}@${requestedVersion}}`)
|
||||
}
|
||||
|
||||
if (!widgetCode) {
|
||||
try {
|
||||
widgetCode = await new Promise(async (resolve, reject) => {
|
||||
await global.storage.getObject(process.env.S3_BUCKET, remoteEntyFilePath, (error, dataStream) => {
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
|
||||
let data = ""
|
||||
|
||||
dataStream.on("data", (chunk) => {
|
||||
data += chunk
|
||||
})
|
||||
|
||||
dataStream.on("end", () => {
|
||||
resolve(data)
|
||||
})
|
||||
|
||||
dataStream.on("error", (error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to fetch widget code. ${error.message}`)
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`🔌 [widget:${widgetId}] Compiling widget code...`)
|
||||
|
||||
widgetCode = await compileWidgetCode(widgetCode, widget.manifest, finalOrigin)
|
||||
|
||||
await global.redis.set(`${origin}:widget:${widgetId}@${requestedVersion}}`, widgetCode)
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to transform widget code. ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
return widgetCode
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user