-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: dynamic import retry plugin [KM-865] #2
base: main
Are you sure you want to change the base?
Conversation
77c17e6
to
9ddda00
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left an initial review; the biggest issue is please back out the changes turning this into a mono repo.
Separately, it would be great if you could please extensively comment the code so that maintenance and future updates are easier.
playground/vitestSetup.ts
Outdated
@@ -0,0 +1,350 @@ | |||
import type * as http from 'node:http' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: I believe most of this was taken from one of the existing vite repos. Are we actually using the entirety of the config or is there any unneeded code here for our purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed most of code that I thought they were not necessary for us.
playground/vue/package.json
Outdated
{ | ||
"name": "@kong-vite-plugin/vue", | ||
"private": true, | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "vue-tsc -b && vite build", | ||
"preview": "vite preview" | ||
}, | ||
"dependencies": { | ||
"vue": "^3.5.13", | ||
"vue-router": "^4.5.0" | ||
}, | ||
"devDependencies": { | ||
"@vitejs/plugin-vue": "^5.2.1", | ||
"@vue/tsconfig": "^0.7.0", | ||
"vue-tsc": "^2.2.0" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: why does the playground need its own package.json file? This isn't a monorepo. Please move dependencies to the root
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can create multiple projects under the playground folder, package.json for each one is necessary, otherwise, how can we manually run those demo projects from the root level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please write up how you envision the testing working?
I’m not sure it makes sense to have fully-standalone applications for testing purposes.
If we need to change to a mono repository then I’d first want to restructure things before merging this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If each package is independent and needs an entire app sandbox I’d almost rather delete this repository and just utilize public-ui-components instead; it’s already set up and would essentially just need a different build command.
For dependencies in the current structure, playground dependencies would be devDependencies in the root package.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial thought was that we might need multiple applications to test different cases, similar to https://github.com/vitejs/vite-plugin-vue/tree/main/playground.
However, we can start simple by writing all use cases in a single project. If more complex scenarios arise, we can refactor it into a monorepo as needed.
/* | ||
Copyright 2024 Carl-Erik Kopseng | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a requirement of an external lib? If yes, can you please add a link to the source?
Also, could this be extracted into its own file and imported where needed rather than inlined into our code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
link added.
No, the code in this function shouldn't have external references, I put detailed reason in comments.
c0a326e
to
73dc74e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some initial feedback.
There is a large lack of comments in the code that would be helpful for review. Please thoroughly comment the code.
id: playwright-cache | ||
uses: actions/cache@v4 | ||
with: | ||
key: playwright-bin-v1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we tie the cache key here to a dynamic string that includes the playwright dependency version from package.json?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! Updated.
"baseUrl": ".", | ||
"outDir": "dist", | ||
"declaration": false, | ||
"declarationDir":null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"declarationDir":null | |
"declarationDir": null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamdehaven Maybe we should enforce this with our shared ESLint config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
const newError = new Error(`[preload-css-retried] ${e.payload.message}`) | ||
throw newError |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const newError = new Error(`[preload-css-retried] ${e.payload.message}`) | |
throw newError | |
throw new Error(`[preload-css-retried] ${e.payload.message}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
"baseUrl": ".", | ||
"outDir": "dist", | ||
"declaration": false, | ||
"declarationDir":null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamdehaven Maybe we should enforce this with our shared ESLint config?
1f0c3c4
to
7cc82d4
Compare
@2eha0 why are you force pushing the branch? You’re obliterating the commit history and it’s impossible to see the changes between commits |
Separate from the changes in the PR, have we done any benchmarking to determine if implementing this plugin in a host application has any performance / timing impacts in the build, or the actual imports themselves? |
Runtime costThis plugin will only work if the module fails to load, which is just one more js function call for the normal case and has no impact on performance. the pseudocode: function importWraper(importFn) {
try {
await importFn() // <- the normal case
} catch () {
// do retry... // <- only run here on error
}
}
importWraper(() => import('xxxx')) // original: () => import('xxx') Comparison of time spent during buildThere's no discernible difference.
https://github.com/Kong/konnect-ui-apps/actions/runs/12758610182/job/35561049472 https://github.com/Kong/konnect-ui-apps/actions/runs/12760560701/job/35566279787?pr=5332 |
I think the performance impact should be rather limited and acceptable. |
We should also investigate how this plugin could impact usage of something like |
Does this plugin, by default, run only against the source code in the repository, or does it also run against all node_modules, etc.? My gut is telling me we would want to exclude node_modules by default since other packages may have their own internal optimizations, desired behavior, etc. We could then potentially allow opting in based on a package name, similar to how rollup marks externals or Vite does optimizeDeps |
| include | string \| RegExp \| (string \| RegExp)[] | Files to include, default is `\.(js\|ts\|vue\|tsx)$`. | | ||
| exclude | string \| RegExp \| (string \| RegExp)[] | Files to exclude. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should likely exclude node_modules
by default, and then allow opting-in where needed.
We should discuss any other desired default configurations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it again today, and I still can’t figure out in what scenarios we would prefer to display an error instead of retrying and then falling back to an exception state when a resource chunk fails to load. In cases like defineAsyncComponent
with a timeout
set, as I understand it, retrying wouldn’t extend the wait time—the timeout would still display an error as expected. If we were to use a dynamic import for something like “feature detection”, it doesn’t seem likely that the distinction would be based on whether the imported module resides in node_modules
. Can you think of any practical examples where retrying would negatively impact the original logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm more suggesting it may be worth testing so we know how it will behave rather than assuming
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Maybe we can add a test case for defineAsyncComponent
? @2eha0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test cases for defineAsyncComponent
have been added.
When the plugin retries the import, does it typically always succeed? I started wondering if the issue is actually rooted in the way we invalidate the cache on AWS. The first request after the cache is invalidated may fail, but would trigger AWS to put the requested file back in the cache. A subsequent request would then have a cache hit, and would successfully download the chunk (similar to SWR behavior). Could we validate this isn't the case in the deployed MFE? |
I believe AWS would not reject requests during revalidation unless the origin is unavailable itself. Additionally, I believe that our JavaScript files shouldn’t invalidate at all, as they all have content hashes in the filenames. |
We manually invalidate the cache for some paths, although not JS that I recall (example) |
- name: Set Playwright path | ||
id: playwright-path | ||
shell: bash | ||
run: echo "PLAYWRIGHT_BROWSERS_PATH=/home/runner/.cache/ms-playwright" >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two issues:
- I believe you actually need to expose this variable to the
$GITHUB_ENV
and then pass this env variable to the step that runs the install command so that Playwright will utilize it during the install - I believe the path should be this:
run: echo "PLAYWRIGHT_BROWSERS_PATH=/home/runner/.cache/ms-playwright" >> $GITHUB_OUTPUT | |
run: echo "PLAYWRIGHT_BROWSERS_PATH=/home/ubuntu/.cache/ms-playwright" >> $GITHUB_ENV |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, and I also replaced /home
to $HOME
id: playwright-install | ||
shell: bash | ||
# does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved | ||
run: pnpm playwright install chromium |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to pass the PLAYWRIGHT_BROWSERS_PATH here as an env variable
@2eha0 , 403 is getting returned when non-existing asset is requested: eg: |
That is correct, if asset is NOT on the edge, request is going to origin , grabs asset from there , spits it back to the requestor and sticks it into CDN. There is |
question: let's assume this is enabled for MFE. Is there any way to see in the datadog:
This allows us to evaluate the usefulness of this plugin :) |
@2eha0 had added two widgets to our DD dashboard (one for JS errors and the other for CSS errors) for current experiments in Once the plugin is published, we’ll install it in |
I still feel like we may be over-optimizing here TBH. |
This isn’t exactly a major pain point, but it’s at least a nice-to-have. The experiment has shown that it is indeed effective, and the community does have similar needs: whatwg/html#6768. |
Summary
KM-865