[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
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

Migrate PerseusWidgetsMap to use a merged interface to represent all available widgets #1936

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

jeremywiebe
Copy link
Collaborator
@jeremywiebe jeremywiebe commented Nov 29, 2024

Summary:

Perseus is designed to be able to support widgets registered into it at runtime. These widgets can be built in a separate npm package or even in the hosting application. As a result, the way that we've defined the widgets prop of PerseusRenderer is too rigid and poses long-term maintenance issues.

As I was working on slitting out the bits of validation from scoring that we'll still be able to do on the client-side, I faced the same challenge (we will have a map of widget IDs for validation).

Working with Kevin Barabash, we figured out a way to define an interface that represents all registered widgets and then use some TypeScript types to generate the PerseusWidgetsMap. This allows us to extend the "known set" of widgets from outside of Perseus.

Although this is not an immediate concern, it will become more and more troublesome to build maps of widget information that are hard-coded to our current set of widgets.

Issue: "none"

Test plan:

yarn typecheck
yarn test

I'll import this npm snapshot into webapp to check that all types are fine there also.

EDIT: I installed the snapshot package in webapp and it type checks! ✅

@jeremywiebe jeremywiebe self-assigned this Nov 29, 2024
Copy link
Contributor
github-actions bot commented Nov 29, 2024

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (5d5e415) and published it to npm. You
can install it using the tag PR1936.

Example:

yarn add @khanacademy/perseus@PR1936

If you are working in Khan Academy's webapp, you can run:

./dev/tools/bump_perseus_version.sh -t PR1936

Copy link
Contributor
github-actions bot commented Nov 29, 2024

Size Change: +788 B (+0.06%)

Total Size: 1.29 MB

Filename Size Change
packages/perseus/dist/es/index.js 423 kB +788 B (+0.19%)
ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 39 kB
packages/keypad-context/dist/es/index.js 760 B
packages/kmath/dist/es/index.js 4.27 kB
packages/math-input/dist/es/index.js 77.9 kB
packages/math-input/dist/es/strings.js 1.79 kB
packages/perseus-core/dist/es/index.js 1.48 kB
packages/perseus-editor/dist/es/index.js 697 kB
packages/perseus-linter/dist/es/index.js 22.2 kB
packages/perseus/dist/es/strings.js 3.7 kB
packages/pure-markdown/dist/es/index.js 3.66 kB
packages/simple-markdown/dist/es/index.js 12.5 kB

compressed-size-action

*
* @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
*/
export interface PerseusWidgetTypes {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Although this looks like the same hard-coded list of widgets as PerseusWidgetsMap is in the "before" state of this PR, the magic is that we can extend this interface from anywhere (even in our own Perseus unit tests if we want to work with a mock widget). Once we've added an entry to this interface, PerseusWidgetsMap automatically know's about that widget!

@jeremywiebe jeremywiebe marked this pull request as ready for review November 29, 2024 21:46
@khan-actions-bot khan-actions-bot requested a review from a team November 29, 2024 21:47
@khan-actions-bot
Copy link
Contributor

Gerald

Required Reviewers
  • @Khan/perseus for changes to .changeset/tender-planets-greet.md, packages/perseus/src/index.ts, packages/perseus/src/perseus-types.ts

Don't want to be involved in this pull request? Comment #removeme and we won't notify you of further changes.

Copy link
Contributor
@SonicScrewdriver SonicScrewdriver left a comment

Choose a reason for hiding this comment

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

This is WAY better than our first attempt, thank you greatly for this work! This seems considerably more maintainable and readable. I'm not seeing anything that should cause any issues with the Extract Perseus Data logic, and if there's no type errors, this gets the all clear from me.

Thank you for adding some truly excellent comments as well. :)

Copy link
Contributor
@kevinb-khan kevinb-khan left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for doing the due diligence to verify that this plan will work. I left a few documentation suggestions in the comments – nothing blocking. 🚢

packages/perseus/src/perseus-types.ts Show resolved Hide resolved
Comment on lines 15 to 42
* Our core set of Perseus widgets.
*
* This interface is the basis for "registering" all Perseus widget types.
* There should be one key/value pair for each supported widget. If you create
* a new widget, an entry should be added to this interface.
*
* Importantly, the key is not important and is not used anywhere outside of
* this interface so it is arbitrary.
*
* If you define the widget outside of this package, you can still add the new
* widget to this interface by writing the following in that pacakge that
* contains the widget. TypeScript will merge that definition of the
* `PerseusWidgets` with the one defined below.
*
* ```typescript
* declare module "@khanacademy/perseus" {
* interface PerseusWidgetTypes {
* Awesomeness: MyAwesomeNewWidget;
* }
* }
*
* type MyAwesomeNewWidget = WidgetOptions<'awesomeness', MyAwesomeNewWidgetOptions>;
* ```
*
* This interface can be extended through the magic of TypeScript "Declaration
* merging". Specifically, we augment this module and extend this interface.
*
* @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for adding this docstring. I think it might also be worth mentioning that MyAwesomeNewWidget needs to be registered and what that looks like, but that might make more sense in the README.md.

Copy link
Member
@catandthemachines catandthemachines left a comment

Choose a reason for hiding this comment

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

Looks like a great improvement! Thanks Jeremy!!

Copy link
Contributor
@handeyeco handeyeco left a comment

Choose a reason for hiding this comment

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

Cool, thanks for digging into this more!

Comment on lines +225 to +227
PerseusWidgetTypes,
MultiItem,
WidgetOptions,
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you know that these will be used in Webapp or are we preemptively exporting them? If not, I wonder if it would be better to keep them internal until we have a use for them externally.

* this interface so it is arbitrary.
*
* If you define the widget outside of this package, you can still add the new
* widget to this interface by writing the following in that pacakge that
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* widget to this interface by writing the following in that pacakge that
* widget to this interface by writing the following in that package that

Radio: RadioWidget;
Sorter: SorterWidget;
Table: TableWidget;
Video: VideoWidget;
Copy link
Contributor

Choose a reason for hiding this comment

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

Not related to your PR and no action needed: can we leverage this or something like this to get rid of basic-widgets, extra-widgets, and all-widgets?

*
* @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
*/
export interface PerseusWidgetTypes {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is a step in the right direction, I just wish we could get to a place where the Renderer-layer of Perseus is completely unaware of the Widget-layer data which would mean finding ways to eliminate these type of widget union/map things.

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.

6 participants