Skip to content

Commit

Permalink
Have the Spring backend serve the new Vue assets.
Browse files Browse the repository at this point in the history
Fixes #154
  • Loading branch information
The4thLaw committed Mar 13, 2024
1 parent 3cc094f commit d226d06
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 94 deletions.
Expand Up @@ -55,9 +55,7 @@ public WebConfig() {

@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/", "classpath:/public/css/");
registry.addResourceHandler("/fonts/**").addResourceLocations("/fonts/", "classpath:/public/fonts/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/", "classpath:/public/js/");
registry.addResourceHandler("/assets/**").addResourceLocations("/assets/", "classpath:/public/assets/");
registry.addResourceHandler("/icons/**").addResourceLocations("/icons/");
registry.addResourceHandler("/favicon.ico").addResourceLocations("/favicon.ico");
}
Expand Down
@@ -1,5 +1,7 @@
package org.demyo.web.controller;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -40,45 +42,14 @@ public class HomeController extends AbstractController {
@Value("#{servletContext.contextPath}")
private String servletContextPath;

@Value("classpath*:public/js/app.*.js")
private Resource[] appJs;
private String appJsFilename;
@Value("classpath*:public/assets/*.js")
private Resource[] allJsResources;
private String indexJsFilename;
private List<String> otherJsFilenames;

@Value("classpath*:public/css/app.*.css")
private Resource[] appCss;
private String appCssFilename;

@Value("classpath*:public/js/manage.*.js")
private Resource[] manageJs;
private String manageJsFilename;

@Value("classpath*:public/css/manage.*.css")
private Resource[] manageCss;
private String manageCssFilename;

@Value("classpath*:public/js/chunk-vendors.*.js")
private Resource[] vendorJs;
private String vendorJsFilename;

@Value("classpath*:public/css/chunk-vendors.*.css")
private Resource[] vendorCss;
private String vendorCssFilename;

@Value("classpath*:public/js/vendor-filepond.*.js")
private Resource[] vendorFilepondJs;
private String vendorFilepondJsFilename;

@Value("classpath*:public/css/vendor-filepond.*.css")
private Resource[] vendorFilepondCss;
private String vendorFilepondCssFilename;

@Value("classpath*:public/js/app-legacy.*.js")
private Resource[] appLegacyJs;
private String appLegacyJsFilename;

@Value("classpath*:public/js/chunk-vendors-legacy.*.js")
private Resource[] vendorLegacyJs;
private String vendorLegacyJsFilename;
@Value("classpath*:public/assets/*.css")
private Resource[] allCssResources;
private List<String> cssFilenames;

private final String appVersion;
private final String appCodename;
Expand All @@ -90,21 +61,30 @@ public HomeController() {

@PostConstruct
private void init() {
// Demyo
appJsFilename = getFrontendResource(appJs, "app.*.js");
appCssFilename = getFrontendResource(appCss, "app.*.css");
manageJsFilename = getFrontendResource(manageJs, "manage.*.js");
manageCssFilename = getFrontendResource(manageCss, "manage.*.css");

// Vendors
vendorJsFilename = getFrontendResource(vendorJs, "chunk-vendors.*.js");
vendorCssFilename = getFrontendResource(vendorCss, "chunk-vendors.*.css");
vendorFilepondJsFilename = getFrontendResource(vendorFilepondJs, "vendor-filepond.*.js");
vendorFilepondCssFilename = getFrontendResource(vendorFilepondCss, "vendor-filepond.*.css");

// Legacy
appLegacyJsFilename = getFrontendResource(appLegacyJs, "app-legacy.*.js");
vendorLegacyJsFilename = getFrontendResource(vendorLegacyJs, "chunk-vendors-legacy.*.js");
Comparator<Resource> indexFirstComp = (r1, r2) -> {
String name1 = r1.getFilename();
String name2 = r2.getFilename();
if (name1.startsWith("index")) {
return -1;
}
if (name2.startsWith("index")) {
return 1;
}
return name1.compareTo(name2);
};

List<Resource> allJs = new ArrayList<>(List.of(allJsResources));
allJs.sort(indexFirstComp);
indexJsFilename = allJs.get(0).getFilename();
otherJsFilenames = allJs.subList(1, allJs.size()).stream().map(Resource::getFilename).toList();

List<Resource> allCss = new ArrayList<>(List.of(allCssResources));
allCss.sort(indexFirstComp);
cssFilenames = allCss.stream().map(Resource::getFilename).toList();

LOGGER.trace("Index JS resource: {}", indexJsFilename);
LOGGER.trace("Sorted non-index JS resources: {}", otherJsFilenames);
LOGGER.trace("Sorted CSS resources: {}", cssFilenames);
}

/**
Expand Down Expand Up @@ -135,18 +115,9 @@ public String index(Model model, HttpServletRequest request, HttpServletResponse
model.addAttribute(MODEL_KEY_VERSION, appVersion);
model.addAttribute(MODEL_KEY_CODENAME, appCodename);

model.addAttribute("appJsFilename", appJsFilename);
model.addAttribute("appCssFilename", appCssFilename);
model.addAttribute("manageJsFilename", manageJsFilename);
model.addAttribute("manageCssFilename", manageCssFilename);

model.addAttribute("vendorJsFilename", vendorJsFilename);
model.addAttribute("vendorCssFilename", vendorCssFilename);
model.addAttribute("vendorFilepondJsFilename", vendorFilepondJsFilename);
model.addAttribute("vendorFilepondCssFilename", vendorFilepondCssFilename);

model.addAttribute("appLegacyJsFilename", appLegacyJsFilename);
model.addAttribute("vendorLegacyJsFilename", vendorLegacyJsFilename);
model.addAttribute("indexJsFilename", indexJsFilename);
model.addAttribute("otherJsFilenames", otherJsFilenames);
model.addAttribute("cssFilenames", cssFilenames);

// The fact that this is a JSP request means that the headers and
// attributes are altered. So the standard header writer attributes
Expand Down
42 changes: 16 additions & 26 deletions source/demyo-web/src/main/webapp/WEB-INF/jsp/index.jsp
Expand Up @@ -8,46 +8,44 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">

<title>Demyo</title>

<meta name="application-name" content="Demyo">
<meta name="mobile-web-app-capable" content="yes">
<%-- The manifest link will be injected by the Vue app -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="Demyo">
<meta name="msapplication-starturl" content="${pageContext.request.contextPath}/">
<%-- In case someone exposes it publicly by mistake --%>
<meta name="robots" content="noindex,nofollow">
<%-- Don't send info to linked sites, this is supposed to be a private application --%>
<meta name="referrer" content="never">

<link rel="copyright" href="${pageContext.request.contextPath}/about">

<c:set var="appleIconSizes" value="${[76, 120, 152, 180]}" scope="application" />
<c:forEach items="${appleIconSizes}" var="size">
<link rel="apple-touch-icon-precomposed" sizes="${size}x${size}" href="${pageContext.request.contextPath}/icons/demyo-${size}-whitebg.png">
</c:forEach>

<c:set var="faviconSizes" value="${[16, 24, 32, 48, 64, 144, 192, 196, 270, 558]}" scope="application" />
<c:forEach items="${faviconSizes}" var="size">
<link rel="icon" sizes="${size}x${size}" href="${pageContext.request.contextPath}/icons/demyo-${size}.png" >
</c:forEach>

<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="${pageContext.request.contextPath}/icons/demyo-144.png">

<link href="${pageContext.request.contextPath}/css/${manageCssFilename}" rel="prefetch">
<link href="${pageContext.request.contextPath}/css/${vendorFilepondCssFilename}" rel="prefetch">
<link href="${pageContext.request.contextPath}/js/${manageJsFilename}" rel="prefetch">
<link href="${pageContext.request.contextPath}/js/${vendorFilepondJsFilename}" rel="prefetch">
<link href="${pageContext.request.contextPath}/css/${appCssFilename}" rel="preload" as="style">
<link href="${pageContext.request.contextPath}/css/${vendorCssFilename}" rel="preload" as="style">
<link href="${pageContext.request.contextPath}/js/${appJsFilename}" rel="modulepreload" as="script">
<link href="${pageContext.request.contextPath}/js/${vendorJsFilename}" rel="modulepreload" as="script">
<link href="${pageContext.request.contextPath}/css/${appCssFilename}" rel="stylesheet">
<link href="${pageContext.request.contextPath}/css/${vendorCssFilename}" rel="stylesheet">

<%-- Note: the nonce is required on external scripts too on Firefox. Chromium Edge doesn't seem to care. --%>
<script type="module" crossorigin src="${pageContext.request.contextPath}/assets/${indexJsFilename}" nonce="${cspScriptNonce}"></script>
<c:forEach items="${otherJsFilenames}" var="asset">
<link rel="modulepreload" crossorigin href="${pageContext.request.contextPath}/assets/${asset}">
</c:forEach>
<c:forEach items="${cssFilenames}" var="asset">
<link rel="stylesheet" crossorigin href="${pageContext.request.contextPath}/assets/${asset}">
</c:forEach>
</head>
<body
data-contextRoot="${pageContext.request.contextPath}/"
Expand All @@ -61,13 +59,5 @@
<strong>We're sorry but the Vue frontend to Demyo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id=app></div>
<%-- Note: the nonce is required on external scripts too on Firefox. Chromium Edge doesn't seem to care. --%>
<script type="module" src="${pageContext.request.contextPath}/js/${vendorJsFilename}" nonce="${cspScriptNonce}"></script>
<script type="module" src="${pageContext.request.contextPath}/js/${appJsFilename}" nonce="${cspScriptNonce}"></script>
<script nonce="${cspScriptNonce}">
!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();
</script>
<script src="${pageContext.request.contextPath}/js/${vendorLegacyJsFilename}" nomodule nonce="${cspScriptNonce}"></script>
<script src="${pageContext.request.contextPath}/js/${appLegacyJsFilename}" nomodule nonce="${cspScriptNonce}"></script>
</body>
</html>

0 comments on commit d226d06

Please sign in to comment.