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

How to make web pages extensible by add-ons? #3187

Open
RumovZ opened this issue May 1, 2024 · 10 comments
Open

How to make web pages extensible by add-ons? #3187

RumovZ opened this issue May 1, 2024 · 10 comments
Labels
web frontend Involves Anki's HTML/CSS/TypeScript/Svelte code

Comments

@RumovZ
Copy link
Collaborator

RumovZ commented May 1, 2024

In the past, there have been different approaches. For both Anki core and add-on development, it would be beneficial to have a consistent approach going forward.
@glutanimate, @abdnh, and any other contributors or add-on authors, your input would be appreciated!

So far we have come up with three different strategies.

1. Svelte components

Add-ons build their own components, while being able to reuse any Anki code they like.

Example: https://github.com/hgiesel/anki_new_format_pack

2. Raw HTML and JS

Add-ons manipulate the DOM directly, with hardly any support from Anki.

Example: https://github.com/ankitects/anki-addons/tree/main/demos/deckoptions_raw_html (not functional)

3. Parameterisation

Anki exposes a strict feature set add-ons can pick from.

Example: #3145 / ankitects/anki-addons#21

Comparison

As a discussion starter, I've tried to summarise the arguments so far. ✔️ means pro and ❌ con. Blank is somewhere in between.
Happy to discuss these or extend the list.

Svelte components Raw HTML & JS Parameterisation
Consistent UX ✔️ ✔️
Maintenance cost (Anki) ✔️
Development cost (add-ons) ✔️
Robustness to Anki changes ✔️
Expressiveness ✔️ ✔️
@RumovZ RumovZ added the web frontend Involves Anki's HTML/CSS/TypeScript/Svelte code label May 1, 2024
@dae
Copy link
Member

dae commented May 2, 2024

I've added an example for number 1, though judging by reviews on https://ankiweb.net/shared/info/1187194862, it's already broken as well.

@abdnh
Copy link
Collaborator

abdnh commented May 6, 2024

The parameterization approach looks simpler to use (no Svelte setup required?) but supporting UI extensions is probably more work with this approach.

I imagine the Svelte components approach is more suitable for certain pages like the graphs page. I like its flexibility and would love to use it in any Svelte page.

@dae
Copy link
Member

dae commented May 6, 2024

There are actually 2 ways we could approach number 1:

a) the current way, where add-ons can make runtime use of the existing components in Anki. Changes in things like props passed to a component would break the add-on
b) by allowing add-on authors to import Anki components at bundle time. This would mean they'd ship with a snapshot of the components at build time, and API changes in new Anki versions should not break their code.

The second approach could potentially be combined with approach 2: use raw HTML/JS if you wish, or use your own Svelte code which happens to import Anki components.

It's not without its own complexities and downsides: we'd need to make it easy to include the components, such as by publishing an NPM library. And our components reference other things like the protobuf TS code, our fluent translations, etc - do we bundle those too? Do we stub them out and still use them dynamically? And how do we pass reactive state into the raw HTML/JS?

But there would be some positives: it largely decouples the add-ons from Anki, making them less likely to break when we refactor, and that breakage would tend to happen when they build their add-on, not when it's run.

@RumovZ
Copy link
Collaborator Author

RumovZ commented May 19, 2024

I was hoping someone with more add-on experience would further the discussion instead. But I'll do my best.

The NPM library seems like the most robust and versatile approach, provided we can overcome the bundling difficulties and you're willing to carry the maintenance burden.

Do we stub them out and still use them dynamically?

As for the protobuf code, is there a difference between bundling the generated code or stubbing it out? I mean, it would break anyway when Anki's protobuf code changes, so I would just do what's simpler to bundle.

As for the fluent translations, bundling them seems preferrable. Add-ons would miss out on translations added later on, but more importantly, there would be no breakages when Anki drops unused strings.
If package size is a concern, maybe translations could be made optional dependencies.

And how do we pass reactive state into the raw HTML/JS?

Isn't it the same as before? I.e. they require a package and subscribe to its stores.

@dae
Copy link
Member

dae commented May 28, 2024

As for the fluent translations, bundling them seems preferrable

That seems like a fair bit of extra work. As you know, we currently embed the translations in the Rust shared library. To bundle them in an npm library, we'd need to ship them separately, and provide a way for the frontend to load them. And different add-ons could be loading different versions. We tend not to delete existing translations quickly when making changes, so I'm not sure it's worth all the extra work to freeze them?

Isn't it the same as before? I.e. they require a package and subscribe to its stores.

With the stores hidden behind a promise, it makes the add-on API a bit more cumbersome, as add-ons wouldn't be able to immediately refer to a $store - so in the case where they're using Svelte and not raw HTML, they'd need to either have derived values that resolve after the promise, or they'd need to use {#await ...} or similar. Not a showstopper though, and it does mean the stores don't need to be nullable.

@popyoung
Copy link

popyoung commented May 31, 2024

Maybe I found a resolution for Raw HTML and JS. Just unpack the code from the function 'setup'.
https://forums.ankiweb.net/t/what-happened-to-my-addon/44965

Relevant pull request: ankitects/anki-addons#22

@RumovZ
Copy link
Collaborator Author

RumovZ commented Jun 1, 2024

I think I need some code to look at at this point. You seem to favour the approach with bundled Svelte components, @dae. Should I try to build an example add-on?

@dae
Copy link
Member

dae commented Jul 22, 2024

Sorry, still struggling to get back to inbox zero - just made it back to this. I think doing an example implementation is a good idea, and in fact, it would probably be valuable to revive the deck options example as well.

The "expose Anki's internal components" hack that we use has broken in the upgrade to Svelte 5, which does not come as a surprise. I think the odds are likely that such breakages will happen again at some point in the future when we upgrade Svelte. Knowing this, it's probably not the wisest choice to further commit to this path.

When you say "bundled Svelte components", I presume what you mean is exposing things like SpinBoxRow in an npm library that users can import? I think that is worth exploring. I assume the basic approach would be to use https://kit.svelte.dev/docs/packaging to package up our code, and have a build script in the example add-on which uses the library to instantiate some components. The bulk of the work is probably on refactoring our code to import a public UI library, and ensuring that UI library doesn't bundle things that we don't want to be distribute separately (translations? protobuf implementation? etc). Things I'd like to look out for are impacts to build/check time, and any other downsides (like reduced typechecking accuracy, though I think Svelte 5 may be on top of that now).

@RumovZ
Copy link
Collaborator Author

RumovZ commented Jul 28, 2024

No worries, from my side we can postpone it until you have the capacity.

The bulk of the work is probably on refactoring our code to import a public UI library

Couldn't Anki continue to use the local files?

I imagine the library would roughly comprise ts/lib/components. Anki would continue to directly import from there, and also have a workflow to bundle and publish it as a package. Add-on authors would pull in this package, build and ship with all their dependencies.

@dae
Copy link
Member

dae commented Aug 5, 2024

No strong feelings at the moment, but one potential problem is the code working correctly when imported locally, but not when published as a separate package, because it references other parts of our codebase. Using the published package might help us catch such issues. I'm not advocating for us to depend on an online package (we still want to be able to build everything locally), just saying it'd be nice to avoid such issues slipping through, perhaps by a "generate package + import into node_modules" step. But there could be other ways to handle that, such as a test suite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
web frontend Involves Anki's HTML/CSS/TypeScript/Svelte code
Projects
None yet
Development

No branches or pull requests

4 participants