Files
fission-console/console/internal/runtime/nodejs.go
T

76 lines
2.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package runtime
import (
"archive/zip"
"bytes"
"encoding/json"
"fmt"
)
// BuildJSDeployZip упаковывает Node.js код в zip для Fission deployment package.
//
// Почему zip, а не просто literal-код:
// Fission node-env v3 поддерживает ESM модули. Чтобы Node.js трактовал файл
// как ESM, нужен package.json с {"type":"module"} рядом с main.js.
// Без него `import` синтаксис вызовет "require is not defined" или SyntaxError.
//
// Почему new Function:
// Пользовательский код пишет CJS-стиль (module.exports = ...) но мы хотим ESM wrapper.
// new Function() изолирует module/exports от глобального ESM контекста и позволяет
// исполнять CJS-код без изменений.
//
// Результат: zip с двумя файлами:
// - package.json: {"type":"module"}
// - main.js: ESM wrapper + инлайн пользовательский код через new Function
func BuildJSDeployZip(code string) ([]byte, error) {
// Сериализуем пользовательский код в JSON строку чтобы безопасно инлайнить
// в JavaScript-литерал — экранирует кавычки, переводы строк, спецсимволы.
codeJSON, err := json.Marshal(code)
if err != nil {
return nil, fmt.Errorf("marshal user code: %w", err)
}
// main.js — ESM wrapper:
// 1. new Function создаёт функцию в пустом модульном контексте (нет import/export)
// 2. Передаём ей module и exports как параметры → пользовательский CJS код работает
// 3. Экспортируем default async function для Fission node-env entrypoint
wrapper := fmt.Sprintf(`const __mod = { exports: {} };
(new Function('module', 'exports', %s))(__mod, __mod.exports);
const _fn = __mod.exports;
export default async function(ctx) {
const fn = typeof _fn === 'function' ? _fn : (_fn.default || _fn.handler || _fn.main);
if (!fn) throw new Error('no exported function found in user code');
const result = await fn(ctx);
if (!result) return { status: 200, body: '' };
if (typeof result.status !== 'undefined') return result;
return { status: 200, ...result };
}
`, string(codeJSON))
var buf bytes.Buffer
zw := zip.NewWriter(&buf)
// package.json: включает ESM режим для всего архива
pkgfw, err := zw.Create("package.json")
if err != nil {
return nil, err
}
if _, err := pkgfw.Write([]byte(`{"type":"module"}`)); err != nil {
return nil, err
}
fw, err := zw.Create("main.js")
if err != nil {
return nil, err
}
if _, err := fw.Write([]byte(wrapper)); err != nil {
return nil, err
}
if err := zw.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}