diff --git a/flow-server/src/main/resources/plugins/application-theme-plugin/application-theme-plugin.js b/flow-server/src/main/resources/plugins/application-theme-plugin/application-theme-plugin.js index 67e373706a2..2835fe78759 100644 --- a/flow-server/src/main/resources/plugins/application-theme-plugin/application-theme-plugin.js +++ b/flow-server/src/main/resources/plugins/application-theme-plugin/application-theme-plugin.js @@ -114,7 +114,7 @@ function handleThemes(themeName, themesFolder, projectStaticAssetsOutputFolder) copyStaticAssets(themeProperties, projectStaticAssetsOutputFolder, logger); - const themeFile = generateThemeFile(themeFolder, themeName); + const themeFile = generateThemeFile(themeFolder, themeName, themeProperties); fs.writeFileSync(path.resolve(themeFolder, themeName + '.js'), themeFile); return true; diff --git a/flow-server/src/main/resources/plugins/application-theme-plugin/package.json b/flow-server/src/main/resources/plugins/application-theme-plugin/package.json index f5edc41a04b..d43bfa2382a 100644 --- a/flow-server/src/main/resources/plugins/application-theme-plugin/package.json +++ b/flow-server/src/main/resources/plugins/application-theme-plugin/package.json @@ -6,7 +6,7 @@ ], "repository": "vaadin/flow", "name": "@vaadin/application-theme-plugin", - "version": "0.2.1", + "version": "0.2.2", "main": "application-theme-plugin.js", "author": "Vaadin Ltd", "license": "Apache-2.0", diff --git a/flow-server/src/main/resources/plugins/application-theme-plugin/theme-generator.js b/flow-server/src/main/resources/plugins/application-theme-plugin/theme-generator.js index bcfb5322afc..3637aed386c 100644 --- a/flow-server/src/main/resources/plugins/application-theme-plugin/theme-generator.js +++ b/flow-server/src/main/resources/plugins/application-theme-plugin/theme-generator.js @@ -44,9 +44,10 @@ export const injectGlobalCss = (css, target) => { * * @param {string} themeFolder folder of the theme * @param {string} themeName name of the handled theme + * @param {JSON Object} themeProperties content of theme.json * @returns {string} theme file content */ -function generateThemeFile(themeFolder, themeName) { +function generateThemeFile(themeFolder, themeName, themeProperties) { const globalFiles = glob.sync('*.css', { cwd: themeFolder, nodir: true, @@ -79,6 +80,15 @@ function generateThemeFile(themeFolder, themeName) { } }); + let i = 0; + if (themeProperties.importCss) { + themeProperties.importCss.forEach((cssPath) => { + const variable = 'module' + i++; + imports.push(`import ${variable} from '${cssPath}';\n`); + globalCssCode.push(`injectGlobalCss(${variable}.toString(), target);\n`); + }); + } + componentsFiles.forEach((componentCss) => { const filename = path.basename(componentCss); const tag = filename.replace('.css', ''); diff --git a/flow-server/src/main/resources/webpack.generated.js b/flow-server/src/main/resources/webpack.generated.js index e66367b86d4..e8793eb1909 100644 --- a/flow-server/src/main/resources/webpack.generated.js +++ b/flow-server/src/main/resources/webpack.generated.js @@ -212,6 +212,9 @@ module.exports = { if(urlResource.match(themePartRegex)){ return /^(\\|\/)theme\1[\s\S]*?\1(.*)/.exec(urlResource)[2].replace(/\\/, "/"); } + if(urlResource.match(/(\\|\/)node_modules\1/)) { + return /(\\|\/)node_modules\1(?!.*node_modules)([\S]*)/.exec(urlResource)[2].replace(/\\/g, "/"); + } return '[path][name].[ext]'; } } diff --git a/flow-tests/test-themes/frontend/theme/app-theme/theme.json b/flow-tests/test-themes/frontend/theme/app-theme/theme.json index d719e3255c5..d56847bae71 100644 --- a/flow-tests/test-themes/frontend/theme/app-theme/theme.json +++ b/flow-tests/test-themes/frontend/theme/app-theme/theme.json @@ -1,4 +1,5 @@ { + "importCss": ["@fortawesome/fontawesome-free/css/all.css"], "assets": { "@fortawesome/fontawesome-free": { "svgs/regular/**": "fortawesome/icons" diff --git a/flow-tests/test-themes/src/main/java/com/vaadin/flow/uitest/ui/theme/ThemeView.java b/flow-tests/test-themes/src/main/java/com/vaadin/flow/uitest/ui/theme/ThemeView.java index 39049d46c66..4e45791c8f4 100644 --- a/flow-tests/test-themes/src/main/java/com/vaadin/flow/uitest/ui/theme/ThemeView.java +++ b/flow-tests/test-themes/src/main/java/com/vaadin/flow/uitest/ui/theme/ThemeView.java @@ -30,6 +30,7 @@ public class ThemeView extends Div { public static final String SNOWFLAKE_ID = "fortawesome"; public static final String BUTTERFLY_ID = "butterfly"; 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 ThemeView() { @@ -45,12 +46,16 @@ public ThemeView() { Span octopuss = new Span(); octopuss.setId(OCTOPUSS_ID); + Span faText = new Span("This test is FontAwesome."); + faText.setClassName("fas fa-coffee"); + faText.setId(FONTAWESOME_ID); + Image snowFlake = new Image( "VAADIN/static/fortawesome/icons/snowflake.svg", "snowflake"); snowFlake.setHeight("1em"); snowFlake.setId(SNOWFLAKE_ID); - add(textSpan, snowFlake, subCss, butterfly, octopuss); + add(textSpan, snowFlake, subCss, butterfly, octopuss, faText); add(new Div()); add(new MyPolymerField().withId(MY_POLYMER_ID)); diff --git a/flow-tests/test-themes/src/test/java/com/vaadin/flow/uitest/ui/theme/ThemeIT.java b/flow-tests/test-themes/src/test/java/com/vaadin/flow/uitest/ui/theme/ThemeIT.java index 98550b4fc3c..5be840b6208 100644 --- a/flow-tests/test-themes/src/test/java/com/vaadin/flow/uitest/ui/theme/ThemeIT.java +++ b/flow-tests/test-themes/src/test/java/com/vaadin/flow/uitest/ui/theme/ThemeIT.java @@ -18,6 +18,7 @@ import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebElement; import com.vaadin.flow.component.html.testbench.ImageElement; @@ -26,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.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; import static com.vaadin.flow.uitest.ui.theme.ThemeView.SNOWFLAKE_ID; @@ -79,6 +81,28 @@ public void applicationTheme_GlobalCss_isUsed() { driver.getPageSource().contains("Could not navigate")); } + @Test + public void applicationTheme_importCSS_isUsed() { + open(); + checkLogsForErrors(); + + Assert.assertEquals( + "Imported FontAwesome css file should be applied.", + "\"Font Awesome 5 Free\"", $(SpanElement.class).id(FONTAWESOME_ID) + .getCssValue("font-family")); + + String iconUnicode = getCssPseudoElementValue(FONTAWESOME_ID, + "::before"); + Assert.assertEquals( + "Font-Icon from FontAwesome css file should be applied.", + "\"\uf0f4\"", iconUnicode); + + getDriver().get(getRootURL() + + "/path/VAADIN/static/@fortawesome/fontawesome-free/webfonts/fa-solid-900.svg"); + Assert.assertFalse("Font resource should be available", + driver.getPageSource().contains("HTTP ERROR 404 Not Found")); + } + @Test public void componentThemeIsApplied_forPolymerAndLit() { open(); @@ -160,4 +184,12 @@ protected String getTestPath() { return path.replace(view, "path/"); } + private String getCssPseudoElementValue(String elementId, + String pseudoElement) { + String script = "return window.getComputedStyle(" + + "document.getElementById(arguments[0])" + + ", arguments[1]).content"; + JavascriptExecutor js = (JavascriptExecutor)driver; + return (String) js.executeScript(script, elementId, pseudoElement); + } }