Skip to content

Commit

Permalink
fix: Resource is not available in java if not referenced in a CSS file (
Browse files Browse the repository at this point in the history
#9776)

Copies static resources from theme folder to a webpack output folder, so that to make them available from Java pages.

Fixes: #9622
# Conflicts:
#	flow-server/src/main/resources/plugins/application-theme-plugin/theme-copy.js
#	flow-tests/test-themes/frontend/themes/app-theme/styles.css
#	flow-tests/test-themes/src/test/java/com/vaadin/flow/uitest/ui/theme/ThemeIT.java
  • Loading branch information
mshabarov authored and pleku committed Mar 12, 2021
1 parent 8c97f5f commit bb93d64
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
],
"repository": "vaadin/flow",
"name": "@vaadin/application-theme-plugin",
"version": "0.3.0",
"version": "0.3.1",
"main": "application-theme-plugin.js",
"author": "Vaadin Ltd",
"license": "Apache-2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,51 @@ const fs = require('fs');
const path = require('path');
const glob = require('glob');

const ignoredFileExtensions = [".css", ".js", ".json"];

/**
* Copy theme static resources to static assets folder. All files in the theme
* folder will be copied excluding css, js and json files that will be
* handled by webpack and not be shared as static files.
*
* @param {string} themeFolder Folder with theme file
* @param {string} projectStaticAssetsOutputFolder resources output folder
* @param {object} logger plugin logger
*/
function copyThemeResources(themeFolder, projectStaticAssetsOutputFolder, logger) {
const staticAssetsThemeFolder = path.resolve(projectStaticAssetsOutputFolder, "themes", path.basename(themeFolder));
if (!fs.existsSync(staticAssetsThemeFolder)) {
require('mkdirp')(staticAssetsThemeFolder);
}
copyThemeFiles(themeFolder, staticAssetsThemeFolder, logger);
}

/**
* Recursively copy files found in theme folder excluding any with a extension found in the `ignoredFileExtensions` array.
*
* Any folders met will be generated and the contents copied.
*
* @param {string} folderToCopy folder to copy files from
* @param {string} targetFolder folder to copy files to
* @param {object} logger plugin logger
*/
function copyThemeFiles(folderToCopy, targetFolder, logger) {
fs.readdirSync(folderToCopy).forEach(file => {
const fileToCopy = path.resolve(folderToCopy, file);
const targetFile = path.resolve(targetFolder, file);

if (fs.statSync(fileToCopy).isDirectory()) {
if (!fs.existsSync(targetFile)) {
fs.mkdirSync(targetFile, {recursive: true});
}
copyThemeFiles(fileToCopy, targetFile, logger);
} else if (!ignoredFileExtensions.includes(path.extname(file))) {
copyFileIfAbsentOrNewer(fileToCopy, targetFile, logger);
}
});
}


/**
* Copy any static node_modules assets marked in theme.json to
* project static assets folder.
Expand All @@ -48,7 +93,7 @@ const glob = require('glob');
* @param {string} themeName name of the theme we are copying assets for
* @param {json} themeProperties theme properties json with data on assets
* @param {string} projectStaticAssetsOutputFolder project output folder where we copy assets to under theme/[themeName]
* @param {logger} theme plugin logger
* @param {object} logger plugin logger
*/
function copyStaticAssets(themeName, themeProperties, projectStaticAssetsOutputFolder, logger) {

Expand Down Expand Up @@ -80,11 +125,7 @@ function copyStaticAssets(themeName, themeProperties, projectStaticAssetsOutputF
});
files.forEach((file) => {
const copyTarget = path.resolve(targetFolder, path.basename(file));
// Only copy if target file doesn't exist or if file to copy is newer
if (!fs.existsSync(copyTarget) || fs.statSync(copyTarget).mtime < fs.statSync(file).mtime) {
logger.trace("Copying: ", file, '=>', targetFolder);
fs.copyFileSync(file, copyTarget);
}
copyFileIfAbsentOrNewer(file, copyTarget, logger);
});
});
});
Expand All @@ -102,4 +143,18 @@ function checkModules(modules) {
return missing;
}

module.exports = {checkModules, copyStaticAssets};
/**
* Copies given file to a given target path, if target file doesn't exist or if
* file to copy is newer.
* @param {string} fileToCopy path of the file to copy
* @param {string} copyTarget path of the target file
* @param {object} logger plugin logger
*/
function copyFileIfAbsentOrNewer(fileToCopy, copyTarget, logger) {
if (!fs.existsSync(copyTarget) || fs.statSync(copyTarget).mtime < fs.statSync(fileToCopy).mtime) {
logger.trace("Copying: ", fileToCopy, '=>', copyTarget);
fs.copyFileSync(fileToCopy, copyTarget);
}
}

module.exports = {checkModules, copyStaticAssets, copyThemeResources};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
const fs = require('fs');
const path = require('path');
const generateThemeFile = require('./theme-generator');
const {copyStaticAssets} = require('./theme-copy');
const {copyStaticAssets, copyThemeResources} = require('./theme-copy');

// matches theme folder name in 'themes/my-theme/my-theme.generated.js'
const nameRegex = /themes\/(.*)\/\1.generated.js/;
Expand Down Expand Up @@ -117,9 +117,8 @@ function handleThemes(themeName, themesFolder, options, logger) {
"Please verify that dependency is added or theme folder exists.")
}
}

copyStaticAssets(themeName, themeProperties, options.projectStaticAssetsOutputFolder, logger);

copyThemeResources(themeFolder, options.projectStaticAssetsOutputFolder, logger);
const themeFile = generateThemeFile(themeFolder, themeName, themeProperties, !options.devMode);

fs.writeFileSync(path.resolve(themeFolder, themeName + '.generated.js'), themeFile);
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions flow-tests/test-themes/frontend/themes/app-theme/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,15 @@ body {
margin: 5px;
padding: 5px;
}

#dice {
width: 300px;
height: 300px;
display: block;
}

p.global {
color: rgba(255, 255, 0, 1); /* yellow */
font-size: 20px;
margin: 2px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class ThemeView extends Div {
public static final String OCTOPUSS_ID = "octopuss";
public static final String FONTAWESOME_ID = "font-awesome";
public static final String SUB_COMPONENT_ID = "sub-component";
public static final String DICE_ID = "dice";

public ThemeView() {
final Span textSpan = new Span("This is the theme test view");
Expand All @@ -60,7 +61,13 @@ public ThemeView() {
snowFlake.setHeight("1em");
snowFlake.setId(SNOWFLAKE_ID);

add(textSpan, snowFlake, subCss, butterfly, octopuss, faText);
Span diceImageSpan = new Span();
diceImageSpan.getStyle().set("background-image",
"url('themes/app-theme/img/dice.jpg')");
diceImageSpan.setId(DICE_ID);

add(textSpan, snowFlake, subCss, butterfly, octopuss, faText,
diceImageSpan);

add(new Div());
add(new MyPolymerField().withId(MY_POLYMER_ID));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.vaadin.testbench.TestBenchElement;

import static com.vaadin.flow.uitest.ui.theme.ThemeView.BUTTERFLY_ID;
import static com.vaadin.flow.uitest.ui.theme.ThemeView.DICE_ID;
import static com.vaadin.flow.uitest.ui.theme.ThemeView.FONTAWESOME_ID;
import static com.vaadin.flow.uitest.ui.theme.ThemeView.MY_LIT_ID;
import static com.vaadin.flow.uitest.ui.theme.ThemeView.MY_POLYMER_ID;
Expand All @@ -36,6 +37,23 @@

public class ThemeIT extends ChromeBrowserTest {


@Test
public void referenceResourcesOnJavaSideForStyling_stylesAreApplied() {
open();
final String resourceUrl = getRootURL()
+ "/path/themes/app-theme/img/dice.jpg";
WebElement diceSpan = findElement(By.id(DICE_ID));
final String expectedImgUrl = "url(\"" + resourceUrl + "\")";
Assert.assertEquals(
"Background image has been referenced on java page and "
+ "expected to be applied",
expectedImgUrl, diceSpan.getCssValue("background-image"));
getDriver().get(resourceUrl);
Assert.assertFalse("Java-side referenced resource should be served",
driver.getPageSource().contains("HTTP ERROR 404 Not Found"));
}

@Test
public void secondTheme_staticFilesNotCopied() {
getDriver().get(getRootURL() + "/path/themes/app-theme/img/bg.jpg");
Expand Down

0 comments on commit bb93d64

Please sign in to comment.