Skip to content
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

Dynamic component #2 #767

Closed
wants to merge 2 commits into from
Closed

Dynamic component #2 #767

wants to merge 2 commits into from

Conversation

Dreamsorcerer
Copy link
Member

@Dreamsorcerer Dreamsorcerer commented Aug 8, 2023

This version works, and has the advantage that a module for a custom component will only be ~1 KB. Another advantage is that (if the component doesn't import anything outside of the global object), then these components can be written as vanilla JS without any compiler.

However, the disadvantages are that it is quite awkward, won't work with existing 3rd-party components and JSX can't be used with it. If a component requires other react/react-admin functions, which are not already imported in the main application, then it may also not work.

Comment on lines 1 to 2
export const g = {"Queue": null, "Link": null, "stringify": null, "Button": null,
"createElement": null, "useRecordContext": null, "useCreatePath": null}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We start by defining a global object that contains all the react functions etc. that we want as the keys, with values initialised to null.

const {
label = "Copy to US",
scrollToTop = true,
icon = g.createElement(g.Queue),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we use the functions from the global object the same as we would if we had imported them normally.

We can't use JSX here, because it will evaluate to null at compile time and not work at all.

Comment on lines +90 to +91
for (const k of Object.keys(mod.g))
mod.g[k] = COMPONENTS[k]
Copy link
Member Author

@Dreamsorcerer Dreamsorcerer Aug 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main application, after dynamically importing the module, simply loops through the module's global object and inserts all the functions it asks for.

This means the module's components will be using the actual same react functions as the main application, and therefore have the same context etc. required to make the component work correctly.

Copy link

@Anthony-E-B Anthony-E-B Aug 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Dreamsorcerer coming from SO as discussed. Would like to have docs or steps to maybe set up an environment where I can reproduce your issue and try out things. If that's too much work you should not bother because there's a tiny chance I can really take a deep look at it. Will try tho. Thanks

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the base project is in Python, if you're on Mac/Linux then you'll already have it installed, so should only take a couple of minutes to run.

  • Clone this branch and cd aiohttp-admin.
  • Install python dependencies: pip install -r requirements.txt
  • Build the JS module: cd admin-js; yarn install; yarn build
  • Try the example:
    • cd ../examples
    • PYTHONPATH='..' python simple.py
    • Go to http://localhost:8080/admin
    • You can login with admin/admin and see the basic project working.

If you click on one of the rows to get to the show view, you'll see the custom button created in the examples:
image

The custom button is loaded from examples/custom-button.js. If you want to try building something with yarn or similar, you can just create a new project and copy the output file over custom-button.js.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Anthony-E-B I had an idea, maybe you might know if it's workable and how to go about it?

I was thinking that maybe I could find a way to replace react in a project's dependencies with some kind of shim.

e.g. I want to use a 3rd-party component, and they have react listed as a dependency. In my build configuration, I replace react with my custom library (no idea how this is done, but presumably it must be possible so people can use patched versions of a library etc.). That custom library has all the same functions as react, except that it will actually proxy the calls to the main application.

So, essentially we replace react in the build script in order to build the component without react being in the compiled module. Then when we import that module from the main application, the module will send all those react calls to the main application, which will use the version of react already compiled in there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this can be used for replacing react:
https://github.com/nerdchacha/module-replace-webpack-plugin

Although doesn't appear to be maintained. Then I just need to figure out a way to build the shim and proxy the calls through.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Anthony-E-B If you're interested, I've come up with a solution in #804.

I think the only thing that would be nice to improve, is having some way to import react-admin/react-router-dom components when they are not included in the shim (because adding all of react-admin to the shim increases the application size by 400KB) with some kind of fallback mechanism in the build process.

@aio-libs aio-libs deleted a comment from codecov bot Aug 8, 2023
@codecov
Copy link

codecov bot commented Aug 9, 2023

Codecov Report

Merging #767 (dac1e53) into master (61e0c0d) will not change coverage.
Report is 2 commits behind head on master.
The diff coverage is n/a.

@@           Coverage Diff           @@
##           master     #767   +/-   ##
=======================================
  Coverage   97.45%   97.45%           
=======================================
  Files          15       15           
  Lines        2118     2118           
  Branches      334      334           
=======================================
  Hits         2064     2064           
  Misses         26       26           
  Partials       28       28           
Flag Coverage Δ
unit 97.35% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@Dreamsorcerer Dreamsorcerer deleted the dynamic-components2 branch December 23, 2023 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants