Skip to content
This repository has been archived by the owner on May 31, 2024. It is now read-only.

Magical replacement of Components #2549

Closed
eric-burel opened this issue Mar 18, 2020 · 3 comments
Closed

Magical replacement of Components #2549

eric-burel opened this issue Mar 18, 2020 · 3 comments

Comments

@eric-burel
Copy link
Contributor

eric-burel commented Mar 18, 2020

Dream goal

Goal is to replace the dynamic Component replacing pattern by explicit exports that would "magically" replace components.

Imagine a component structured like this:

// datatable.js
const DatatableHeader = () => (<header>default header</header>)

const DatatableFooter = () => (<footer>default footer</footerr>)

const DatatableContent = ({children}) => (
    <div>
        <DatableaHeader />
            {children}
        <DatatableFooter />
</div>

const Datatable = () => (
    <div>
        <DatatableContent />
    </div>
)

You may want to replace the Header, and the Content with your own components:

// my-overrides.js, a special file that contains my Vulcan components override. Could be detected at build time.
export * from "vulcan/ui-react" // magically imports DatatableFooter, DatatableHeader, DatatableContent and Datatable
export const DatatableHeader = () => (<header> I AM OVERRIDEN </header>) // first override
export const DatatableContent = () => (<div><DatatableHeader/> <div> Hello </div> <DatatableFooter /></div> // second override

Then you consume them like this, business as usual:

// my-page.js
import { Datatable } from "vulcan/ui-react" // import default components + my custom override

export const MyPage = () => (<Datatable>Hello!</Datatable>) // DatatableContent has magically been replaced in Datatable

It's probably undoable with Meteor, but it could prove doable with Webpack.
The tricky part is that you want to override only certain component, that are themselves nested into other replaceable component. You get a kind of recursive/circular import issue.

What's doable today

This pattern is already implementable with one level of imports like this:

// my-ui.js
export * from "vulcan/react"
export const DatatableHeader = () => (...) // will reexport, overriding default DatatableHeader from "vulcan/react"

but it's not enough to handle more deeply nested component replacement, for complex components like DataTable or SmartForm that have multiple layers of replaceable component.

Possible implementation

Step 1: detecting "magic" replacement

First step is defining a syntax for magic components.

Possibilities:

  • Prefixing components, eg <@Datatable>: can be detected component by component but it's not very clean

  • "Magic import syntax", eg import { ComponentToReplace } from "vulcan/magic-component"/ export * from "vulcan/magic-components": detect that we want to import "magic components" or override them

  • a special file name for files that exports component override

  • explicitely declaring dependencies between components eg export { component: Datatable, dependsOnMagic: ["DatatableContents"] }

Step 2: build

The difficulty is to handle deeply nested replaceable component.

  • Datatable is defined with default components
  • We detect that DatatableFooter is overridden by user
  • We rebuild DatatableContents with overridden DatatableFooter export
  • We rebuild Datatable, which depends on DatatableContents which contains an overridden export.

The build would probably look like a recursive structure or a tree, where we rebuild everything until all nested components are replaced by user's overrides.

@EloyID @juliensl that's for you Material UI users

@eric-burel
Copy link
Contributor Author

Any brain familiar with Webpack welcome. We could also tag those component with a specific syntax to allow static analysis, like naming them <@Datatable> for example

@eric-burel
Copy link
Contributor Author

A first iteration could be dropping "Components" population at runtime and replace it by an additional build step #2406
This way "Components.DatatableHeader" could be defined correctly (and maybe overridden) before the app would even start.

@eric-burel
Copy link
Contributor Author

Now tracked on VulcanJS/vulcan-npm#17

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant