Files
directus/packages/shared/src/utils/load-extensions.ts
Nicola Krumschmidt 051df415df Fix extensions (#6377)
* Add support for npm extensions

* Allow extensions to import vue from the main app

* Bundle app extensions on server startup

* Fix return type of useLayoutState

* Add shared package

* Add extension-sdk package

* Add type declaration files to allow deep import of shared package

* Add extension loading to shared

* Refactor extension loading to use shared package

* Remove app bundle newline replacement

* Fix extension loading in development

* Rename extension entrypoints

* Update extension build instructions

* Remove vite auto-replacement workaround

* Update package-lock.json

* Remove newline from generated extension entrypoint

* Update package-lock.json

* Build shared package as cjs and esm

* Move useLayoutState composable to shared

* Reverse vite base env check

* Share useLayoutState composable through extension-sdk

* Update layout docs

* Update package versions

* Small cleanup

* Fix layout docs

* Fix imports

* Add nickrum to codeowners

* Fix typo

* Add 'em to vite config too

* Fix email

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
2021-06-23 12:43:06 -04:00

96 lines
3.1 KiB
TypeScript

import path from 'path';
import fse from 'fs-extra';
import { AppExtensionType, Extension } from '../types';
import { resolvePackage } from './resolve-package';
import { listFolders } from './list-folders';
import { EXTENSION_NAME_REGEX, EXTENSION_TYPES } from '../constants';
import { pluralize } from './pluralize';
export async function getPackageExtensions(root: string): Promise<Extension[]> {
const pkg = await fse.readJSON(path.resolve(path.join(root, 'package.json')));
const extensionNames = Object.keys(pkg.dependencies).filter((dep) => EXTENSION_NAME_REGEX.test(dep));
return listExtensionsChildren(extensionNames);
async function listExtensionsChildren(extensionNames: string[], root?: string) {
const extensions: Extension[] = [];
for (const extensionName of extensionNames) {
const extensionPath = resolvePackage(extensionName, root);
const extensionPkg = await fse.readJSON(path.join(extensionPath, 'package.json'));
if (extensionPkg['directus:extension'].type === 'pack') {
const extensionChildren = Object.keys(extensionPkg.dependencies).filter((dep) =>
EXTENSION_NAME_REGEX.test(dep)
);
const extension: Extension = {
path: extensionPath,
name: extensionName,
version: extensionPkg.version,
type: extensionPkg['directus:extension'].type,
host: extensionPkg['directus:extension'].host,
children: extensionChildren,
local: false,
root: root === undefined,
};
extensions.push(extension);
extensions.push(...(await listExtensionsChildren(extension.children || [], extension.path)));
} else {
extensions.push({
path: extensionPath,
name: extensionName,
version: extensionPkg.version,
type: extensionPkg['directus:extension'].type,
entrypoint: extensionPkg['directus:extension'].path,
host: extensionPkg['directus:extension'].host,
local: false,
root: root === undefined,
});
}
}
return extensions;
}
}
export async function getLocalExtensions(root: string): Promise<Extension[]> {
const extensions: Extension[] = [];
for (const extensionType of EXTENSION_TYPES) {
const typeDir = pluralize(extensionType);
const typePath = path.resolve(path.join(root, typeDir));
try {
const extensionNames = await listFolders(typePath);
for (const extensionName of extensionNames) {
const extensionPath = path.join(typePath, extensionName);
extensions.push({
path: extensionPath,
name: extensionName,
type: extensionType,
entrypoint: 'index.js',
local: true,
root: true,
});
}
} catch (err) {
if (err.code === 'ENOENT') throw new Error(`Extension folder "${typePath}" couldn't be opened`);
throw err;
}
}
return extensions;
}
export function generateExtensionsEntry(type: AppExtensionType, extensions: Extension[]): string {
const filteredExtensions = extensions.filter((extension) => extension.type === type);
return `${filteredExtensions
.map((extension, i) => `import e${i} from '${path.resolve(extension.path, extension.entrypoint || '')}';\n`)
.join('')}export default [${filteredExtensions.map((_, i) => `e${i}`).join(',')}];`;
}