Resources support

Signed-off-by: Aleksandr Veselov <veselov.aleksandr@huawei.com>
This commit is contained in:
Aleksandr Veselov 2023-12-01 16:51:02 +03:00
parent 614db0d47e
commit 6fcd453afe

View File

@ -20,6 +20,7 @@ import {
export function makeArkoalaPlugin() {
const ARKOALA_ENTRY_STUB = '@koalaui/arkoala-app';
const ARKOALA_RESOURCES_MODULE = '@koalaui/arkoala-app-resources';
let arkoalaBuildPath = '';
let arkoalaGeneratedPath = '';
@ -149,6 +150,11 @@ export function makeArkoalaPlugin() {
if (source === ARKOALA_ENTRY_STUB) {
return { id: ARKOALA_ENTRY_STUB, external: true };
}
if (source === ARKOALA_RESOURCES_MODULE) {
return { id: ARKOALA_RESOURCES_MODULE, external: true };
}
if (options.isEntry && source.endsWith('.ets')) {
// TODO resolve with node-loader?
console.log('RESOLVE' + source);
@ -178,7 +184,6 @@ export function makeArkoalaPlugin() {
let bundle = await rollup.rollup({
input: generatedPath,
// external: [ARKOALA_ENTRY_STUB],
plugins: [
nodeResolve({
modulePaths: [
@ -205,12 +210,20 @@ export function makeArkoalaPlugin() {
if (source === ARKOALA_ENTRY_STUB) {
return '\0' + ARKOALA_ENTRY_STUB;
}
if (source === ARKOALA_RESOURCES_MODULE) {
return { id: '\0' + ARKOALA_RESOURCES_MODULE, moduleSideEffects: true };
}
},
load(id) {
if (id === '\0' + ARKOALA_RESOURCES_MODULE) {
return { code: genResourceMapModule() }
}
if (id === '\0' + ARKOALA_ENTRY_STUB) {
return {
code: `
import { ArkoalaControl, startApplication } from "@koalaui/arkoala"
import ${JSON.stringify(ARKOALA_RESOURCES_MODULE)}
import { startApplication } from "@koalaui/arkoala"
import { ArkRooted } from "@koalaui/arkoala-arkui"
import { __Entry } from ${JSON.stringify(
path.join(arkoalaGeneratedMemoPath, 'pages/Index')
@ -261,3 +274,88 @@ export function makeArkoalaPlugin() {
},
};
}
function genResourceMapModule(options: CodegenOptions = {}) {
const moduleJsonPath = projectConfig.aceModuleJsonPath;
const resourceTablePath = path.join(path.dirname(moduleJsonPath), 'ResourceTable.txt');
const importString = options.arkoalaImport ?? "@koalaui/arkoala-arkui"
const module = readModuleManifest(moduleJsonPath);
const resourceTable = readResourceTable(resourceTablePath);
const resourceMap = makeResourceMap(resourceTable)
return [
`import { __registerResources, _r, _rawfile } from ${JSON.stringify(importString)};\n\n`,
`const bundleName = ${JSON.stringify(module.bundleName || "")};\n`,
`const moduleName = ${JSON.stringify(module.moduleName || "")};\n`,
`const resources = ${JSON.stringify(resourceMap || {}, null, 4)};\n\n`,
`__registerResources(bundleName, moduleName, resources);\n`,
`export function $r(name, ...args) { return _r(name, ...args) };\n`,
`export function $rawfile(name) { return _rawfile(name) };\n`,
`Object.assign(globalThis, { $r: $r, $rawfile: $rawfile });\n`, // TODO: replace with plugin-inject
].join('');
}
interface ResourceTableEntry {
type: string
name: string
id: number
}
interface ModuleInfo {
bundleName: string
moduleName: string
}
function readResourceTable(filepath: string): ResourceTableEntry[] {
let content = fs.readFileSync(filepath, "utf-8").trim()
let lines = content.split(/(\r?\n)+/gm)
let entries: ResourceTableEntry[] = []
for (const line of lines) {
let items = line.trim().split(/\s+/g);
if (items.length === 0 || items[0] === "") continue;
if (items.length !== 3) {
throw new Error(`Illegal resource table format (at line '${items}')`)
}
const [type, name, idStr] = items
if (!/^0x[0-9A-Fa-f]{8}$/i.test(idStr)) { // int32 in hex, 0xFFFFFFFF
throw new Error(`Illegal resource id: ${idStr}`)
}
const id = parseInt(idStr, 16)
entries.push({ type, name, id })
}
return entries
}
function readModuleManifest(filepath: string): ModuleInfo {
let json = fs.readFileSync(filepath, "utf-8").trim()
let manifest = JSON.parse(json)
let moduleName = manifest.module.name
let bundleName = manifest.app?.bundleName ?? "com.huawei.arkoala" // TODO remove hardcoded constant
return { moduleName, bundleName }
}
function makeResourceMap(resources: ResourceTableEntry[]): Record<string, number> {
let output = {};
for (const {type, name, id} of resources) {
let key = type + "." + name
if (key in output) {
throw new Error(`Duplicated resource key: ${key}`)
}
output[key] = id
}
return output
}
interface CodegenOptions {
arkoalaImport?: string
}