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

SWC-7242 #5630

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
Open

SWC-7242 #5630

wants to merge 11 commits into from

Conversation

nickgros
Copy link
Contributor

  • Add Vite integration to bundle and emit assets
  • Update HtmlInjectionFilter to inject a CDN endpoint and Vite asset tags
  • Update Portal.html to use injected CDN endpoint and injected Vite asset tags
  • Add script that bundles React, ReactDOM, ReactQuery, SRC, MUI components and adds them to the window object (replacing UMD scripts in Portal.html)
  • Migrate from yarn to pnpm
  • Update dependencies to match those that are actually used (required by pnpm) and remove some that are unused.

Depends on a synapse-react-client release containing Sage-Bionetworks/synapse-web-monorepo#1565

@@ -0,0 +1,26 @@
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Vite will bundle this file, and the bundled asset will be emitted in the Portal HTML.

This will replace the various UMD bundles that many packages are no longer providing.

@@ -1,6 +1,13 @@
{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

While it looks like we added a bunch of new dependencies, most of these are not new. With yarn v1, we could directly depend on artifacts from transitive dependencies. pnpm does not let you do this, so we have to add add those previously-transitive dependencies that we currently directly depend on.

Comment on lines -18 to -19
"markdown-it-sub": "^2.0.0",
"markdown-it-sup": "^2.0.0",
Copy link
Contributor Author

@nickgros nickgros Feb 12, 2025

Choose a reason for hiding this comment

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

These were not used. We were already using the -alt packages, they just were not explicitly listed as dependencies.

Comment on lines +67 to +68
"vite": "^6.0.11",
"vite-plugin-node-polyfills": "0.17.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add Vite

"dev:codeserver": "mvn clean gwt:run-codeserver",
"dev:watcher": "wait-on tcp:127.0.0.1:9876 && mvn fizzed-watcher:run",
"dev:tomcat": "wait-on tcp:127.0.0.1:9876 && docker pull tomcat:9.0; docker run --name swc-dev --rm -p 8888:8080 -v \"/$(pwd)/target/portal-develop-SNAPSHOT/:/usr/local/tomcat/webapps/ROOT/\" -v \"/$HOME/.m2/settings.xml\":/root/.m2/settings.xml tomcat:9.0",
"dev:tomcat": "wait-on tcp:127.0.0.1:9876 && docker pull tomcat:9.0; docker run --name swc-dev --rm -p 8888:8080 -v \"/$(pwd)/target/portal-develop-SNAPSHOT/:/usr/local/tomcat/webapps/ROOT/\" -v \"/$HOME/.m2/settings.xml\":/root/.m2/settings.xml -e CATALINA_OPTS=\"-Dorg.sagebionetworks.web.client.dev.mode=true\" tomcat:9.0",
"dev:vite": "vite dev",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add a script that runs the Vite dev server (live reloading of assets bundled by Vite)

"dev:codeserver": "mvn clean gwt:run-codeserver",
"dev:watcher": "wait-on tcp:127.0.0.1:9876 && mvn fizzed-watcher:run",
"dev:tomcat": "wait-on tcp:127.0.0.1:9876 && docker pull tomcat:9.0; docker run --name swc-dev --rm -p 8888:8080 -v \"/$(pwd)/target/portal-develop-SNAPSHOT/:/usr/local/tomcat/webapps/ROOT/\" -v \"/$HOME/.m2/settings.xml\":/root/.m2/settings.xml tomcat:9.0",
"dev:tomcat": "wait-on tcp:127.0.0.1:9876 && docker pull tomcat:9.0; docker run --name swc-dev --rm -p 8888:8080 -v \"/$(pwd)/target/portal-develop-SNAPSHOT/:/usr/local/tomcat/webapps/ROOT/\" -v \"/$HOME/.m2/settings.xml\":/root/.m2/settings.xml -e CATALINA_OPTS=\"-Dorg.sagebionetworks.web.client.dev.mode=true\" tomcat:9.0",
Copy link
Contributor Author

@nickgros nickgros Feb 12, 2025

Choose a reason for hiding this comment

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

Add environment variable org.sagebionetworks.web.client.dev.mode=true, which tells the servlet that we are running in dev mode and to use the Vite dev server.

Comment on lines +84 to +87
// ViteManifestProviderImpl requires ServletContext, which cannot be injected, so we create the singleton here.
private ViteManifestProvider viteManifestProviderSingleton;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a better way to do this?

Comment on lines +104 to +132
filter("/*").through(SSLFilter.class);
bind(SSLFilter.class).in(Singleton.class);

filter("*").through(HtmlInjectionFilter.class);
bind(HtmlInjectionFilter.class).in(Singleton.class);

filter("/*").through(GWTCacheControlFilter.class);
bind(GWTCacheControlFilter.class).in(Singleton.class);

filter("/js/*").through(GWTAllCacheFilter.class);
filter("/images/*").through(GWTAllCacheFilter.class);
filter("/research/*").through(GWTAllCacheFilter.class);
bind(GWTAllCacheFilter.class).in(Singleton.class);

filter("/*").through(JavaScriptContentTypeFilter.class);
bind(JavaScriptContentTypeFilter.class).in(Singleton.class);

filter("/*").through(HSTSFilter.class);
bind(HSTSFilter.class).in(Singleton.class);

filter("/*").through(CORSFilter.class);
bind(CORSFilter.class).in(Singleton.class);

filter("/*").through(XFrameOptionsFilter.class);
bind(XFrameOptionsFilter.class).in(Singleton.class);
Copy link
Contributor Author

@nickgros nickgros Feb 12, 2025

Choose a reason for hiding this comment

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

Removed filters from web.xml and added them here, preserving the filter order. This allows us to inject dependencies into the filter objects.

Comment on lines 180 to 205
private void addCdnEndpoint(
Map<String, String> dataModel,
HttpServletRequest request
) {
String origin = request.getHeader("origin");
if (origin != null && CDN_ORIGINS_REGEX.matcher(origin).matches()) {
dataModel.put(CDN_ENDPOINT_KEY, "//cdn-" + request.getHeader("origin"));
} else {
dataModel.put(CDN_ENDPOINT_KEY, "");
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved logic to determine the CDN endpoint to this filter, instead of JavaScript in the HTML file itself. Logic should be the same.

Comment on lines 192 to 232
/**
* Adds Vite imports to the data model based on the request origin.
* This must be called AFTER the CDN_ENDPOINT_KEY is added to the data model
* @param dataModel
*/
private void addViteImports(Map<String, String> dataModel) {
boolean isDev = "true".equals(System.getProperty(IS_DEV_MODE));
if (isDev) {
dataModel.put(
VITE_IMPORTS_INJECTION_KEY,
ViteHTMLProvider.getViteDevelopmentHTML(VITE_IMPORTED_FILES)
);
} else {
dataModel.put(
VITE_IMPORTS_INJECTION_KEY,
ViteHTMLProvider.getViteProductionHTML(
VITE_IMPORTED_FILES,
viteManifestProvider.getManifest(),
dataModel.get(CDN_ENDPOINT_KEY) + "/generated/vite/"
)
);
}
}
Copy link
Contributor Author

@nickgros nickgros Feb 12, 2025

Choose a reason for hiding this comment

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

Injects scripts for the assets bundled by Vite

@@ -10,7 +10,7 @@

<meta
http-equiv="Content-Security-Policy"
content="default-src 'self' data: blob: 'unsafe-inline' 'unsafe-eval' *.synapse.org *.sagebase.org *.googleapis.com *.gstatic.com *.googletagmanager.com cdn.statuspage.io s3.amazonaws.com www.google-analytics.com kh896k90gyvg.statuspage.io *.youtube.com *.rstudio.com *.google.com *.shinyapps.io *.smartsheet.com sagebionetworks.jira.com 127.0.0.1:9876 esm.sh; frame-ancestors 'self' https://*.synapse.org localhost; img-src * data: blob:; connect-src https://* http://127.0.0.1:8888"
content="default-src 'self' data: blob: 'unsafe-inline' 'unsafe-eval' *.synapse.org *.sagebase.org *.googleapis.com *.gstatic.com *.googletagmanager.com cdn.statuspage.io s3.amazonaws.com www.google-analytics.com kh896k90gyvg.statuspage.io *.youtube.com *.rstudio.com *.google.com *.shinyapps.io *.smartsheet.com sagebionetworks.jira.com 127.0.0.1:9876 esm.sh localhost:5173; frame-ancestors 'self' https://*.synapse.org localhost; img-src * data: blob:; connect-src https://* http://127.0.0.1:8888 http://localhost:5173 ws://localhost:5173"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Vite dev server runs on localhost:5173, need to add to CSP to allow downloading scripts, connecting over HTTP and WebSocket protocols

Comment on lines -98 to -105
var cdnEndpoint = '//cdn-' + location.hostname + '/'
var processEnvironment = 'production'
var synapseOrgRegex = /(www|staging|tst)\.synapse\.org$/

if (!synapseOrgRegex.test(location.hostname)) {
cdnEndpoint = '/'
processEnvironment = 'development'
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Logic for CDN moved to the HtmlInjectionFilter. Vite should handle the processEnvironment logic in the bundling phase.

Comment on lines -142 to -150
let reactPath, reactDomPath

if (processEnvironment === 'production') {
reactPath = cdnEndpoint + 'generated/react.production.min.js'
reactDomPath = cdnEndpoint + 'generated/react-dom.production.min.js'
} else {
reactPath = cdnEndpoint + 'generated/react.development.js'
reactDomPath = cdnEndpoint + 'generated/react-dom.development.js'
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

React/ReactDOM scripts removed, now handled by Vite

loadJs(cdnEndpoint + 'generated/plotly.min.js')
loadJs(cdnEndpoint + 'generated/create-plotly-component.min.js')
loadJs(cdnEndpoint + 'generated/universalCookie.min.js')
loadJs(cdnEndpoint + 'generated/synapse-react-client.production.min.js') // We don't load SRC's scss because we include it in our own compiled scss
Copy link
Contributor Author

Choose a reason for hiding this comment

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

synapse-react-client import removed, now handled by Vite

loadJs(reactPath)
loadJs(reactDomPath)
loadJs(cdnEndpoint + 'generated/material-ui.production.min.js')
loadJs(cdnEndpoint + 'generated/react-transition-group.min.js')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

react-transition-group bundle removed because it is unused

loadJs(cdnEndpoint + 'generated/material-ui.production.min.js')
loadJs(cdnEndpoint + 'generated/react-transition-group.min.js')
loadJs(cdnEndpoint + 'generated/prop-types.min.js')
loadJs(cdnEndpoint + 'generated/react-measure.js')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

react-measure bundle removed because it is unused

loadJs(cdnEndpoint + 'generated/pica.min.js')
loadJs(reactPath)
loadJs(reactDomPath)
loadJs(cdnEndpoint + 'generated/material-ui.production.min.js')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed, now handled by Vite

@@ -6,94 +6,10 @@
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"
>
<filter>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filter instantiation moved to PortalServletModule so dependencies can be injected into these.

- Add Vite integration to bundle and emit assets
- Update HtmlInjectionFilter to inject a CDN endpoint and Vite asset tags
- Update Portal.html to use injected CDN endpoint and injected Vite asset tags
- Add script that bundles React, ReactDOM, ReactQuery, SRC, MUI components and adds them to the window object (replacing UMD scripts in Portal.html)
- Migrate from yarn to pnpm
- Update dependencies to match those that are actually used (required by pnpm) and remove some that are unused.
@@ -5,7 +5,7 @@ env:
BUILD_ARTIFACT_NAME: swc-war
BUILD_DIR: target
BUILD_NAME: portal-develop-SNAPSHOT.war
NODE_VERSION: 18.16.0
NODE_VERSION: 22
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Update Node to 22 (latest LTS) since it includes the latest version of corepack, which we will use to install pnpm.

Copy link
Contributor

@hallieswan hallieswan left a comment

Choose a reason for hiding this comment

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

Looks great to me! It'd be great to run e2e tests locally if possible to confirm that core functionality is unaffected.

- Fix e2e tests
- Fix ReactDOM/ReactDOMClient distinction -- ReactDOMClient only contains `createRoot`
- Prefer `window` over `self`
- Move Vite compilation to `compile` phase -- it does not get copied over if we wait until the `package` phase, even though we don't need it until then.
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