Skip to content

Export Registry #3833

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
SychO9 opened this issue Jun 7, 2023 · 0 comments · Fixed by #3842
Closed

Export Registry #3833

SychO9 opened this issue Jun 7, 2023 · 0 comments · Fixed by #3842

Comments

@SychO9
Copy link
Member

SychO9 commented Jun 7, 2023

What & Why

The export registry is a concept created to give us more control and flexibility over how modules are imported. The idea is to store modules in a registry, from which external exports are translated to access to that registry. This is an important step towards lazy loading modules.

Current system of imports/exports

This is the gist of the current import/export logic in Flarum:

export_registry

  • Core exposes a compat object that maps to core exports (components/Modal => export).
  • Webpack translates imports of core modules to an access to compat.
  • Core does not import its modules from compat.
  • Extensions (like tags and mentions), make their exports accessible by mutating compat (import from flarum/tags/..).
  • Extensions also do not import their own modules from compat.
  • Besides compat there is extensions object which maps to an extension's main exports.

Goals

Essential Nice to have
- Formalise into an exports registry API - Overriding imports, it would require core and extension local imports to rely on the registry.
- Allow extending/overriding components asynchronously (for lazy loading later on).
- Auto load all exports into the registry (making compat redundant).
- Allow determining public vs private API.

Brainstormed system

This is the formalized concept brainstormed by @askvortsov1 in early 2021.

export_registry_after

interface ExportRegistry {
    /**
     * Add an instance to the registry.
     * This serves as the equivalent of `flarum.core.compat[id] = object`
     */
    add(namespace: string, id: string, object: any);

    /**
     * Add a function to run when object of id "id" is added (or overriden).
     * If such an object is already registered, the handler will be applied immediately.
     */
    onLoad(namespace: string, id: string, handler: Function);

    /**
     * Retrieve an object of type `id` from the registry.
     */
    get(namespace: string, id: string): any;
}

Every module source will be appended by a custom Webpack loader, with flarum.reg.add($namespace, $path, $module) and every import from another package will be translated to a flarum.reg.get($name, $path) Giving us full control over loading modules and exposing them. One of the added benefits of this is no longer needing to explicitly add things to a compact API to be used externally.

  • Exports from core and extensions are auto-loaded into the registry (through webpack).
  • Webpack translates non-local imports to an access to the registry.
  • Each export is keyed by an ID (namespace + path + name).
  • The registry allows listening to the addition of an export. (Useful for lazy loading).

Namespace & ID

Exports will be identified and registered with:

  • a namespace (the usual extension ID format, we will use core for core and for example flarum-tags or blomstra-realtime for extensions).
  • an ID, which is the path of the module within the package, for example, common/components/Acme.

Then:

  • When importing flarum/_path_/module.js, it will be translated to a namespace of core and ID of _path_/module.
  • For extensions, the import format will be ext:blomstra/realtime/_path_/module.js, interpreted as namespace=blomstra-realtime and ID=_path_/module.

Open challenges

  • When a module that has not been loaded yet (code splitting) is imported, what should the registry return?
  • How to allow separation between public and private API?

Export/Import formats

The following scenarios are not supported:

Exports that will not be added to the registry

When using an unnamed export, the module cannot be added to the registry, unless that is a wanted behavior on your part, make sure to have names on exports. Examples:

// Will not be added to the registry
export default function () {
    return 'anonymous';
};

// Will be added
export default function acme() {
    return 'anonymous';
};
// Will not be added to the registry
import Model from './Model';
import PostTypes from './PostTypes';
import Routes from './Routes';
import Store from './Store';

export default {
  Model,
  PostTypes,
  Routes,
  Store,
};

// Will be added
import Model from './Model';
import PostTypes from './PostTypes';
import Routes from './Routes';
import Store from './Store';

const extenders = {
  Model,
  PostTypes,
  Routes,
  Store,
};

export default extenders;

Supported Exports/Imports across extensions

There are 3 ways you can export modules to be imported from other extensions

Module file with a default export only
// Extension A: vendor/extension-a
// Filename: moduleA.ts
// Export
export default ...;

// Extension B: vendor/extension-b
// Import
import moduleA from 'ext:vendor/extension-a/.../moduleA';
Module with exports only (no default export)
// Extension A: vendor/extension-a
// Filename: moduleA.ts
// Export
export function acme() {}
export class Test {}
const foo = 'foo';
export { foo };

// Extension B: vendor/extension-b
// Import
import { acme, Test, foo } from 'ext:vendor/extension-a/.../moduleA';
Directory with modules and an index.js

See core for an example extenders.

// Can import as
import Routes from 'flarum/common/extenders/Routes';
// Or
import { Model, PostTypes } from 'flarum/common/extenders';
// Or
import Extend from 'flarum/common/extenders';

Breaking Changes

  • Importing from flarum/tags or flarum/suspend or flarum/mentions or flarum/flags no longer works, instead use ext:flarum/tags ..etc.
  • Importing from @flarum/core no longer works.
  • Webpack config's useExtensions option has been removed, use the import formats explained above instead.
@SychO9 SychO9 added this to the 2.0 milestone Jun 7, 2023
@SychO9 SychO9 self-assigned this Jun 7, 2023
@SychO9 SychO9 changed the title Export Registry Brainstorm Export Registry Jun 7, 2023
@SychO9 SychO9 mentioned this issue Jun 22, 2023
8 tasks
@SychO9 SychO9 removed this from the 2.0 milestone Jun 22, 2023
@SychO9 SychO9 mentioned this issue Jul 21, 2023
@SychO9 SychO9 added this to Roadmap Aug 2, 2024
@github-project-automation github-project-automation bot moved this to 🚀 future in Roadmap Aug 2, 2024
@SychO9 SychO9 moved this from 🚀 future to ✅ completed in Roadmap Aug 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: completed
Development

Successfully merging a pull request may close this issue.

1 participant