diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateThemeImport.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateThemeImport.java index 6a75be2efc6..b9396694bbb 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateThemeImport.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateThemeImport.java @@ -58,11 +58,10 @@ public void execute() throws ExecutionFailedException { } try { - FileUtils.write(themeImportFile, - "import {applyTheme as _applyTheme} from 'theme/" + theme - .getName() + "/" + theme.getName() - + ".js';\nexport const applyTheme = _applyTheme;\n", - StandardCharsets.UTF_8); + FileUtils.write(themeImportFile, String.format( + "import {applyTheme as _applyTheme} from 'theme/%s/%s.js';%n" + + "export const applyTheme = _applyTheme;%n", + theme.getName(), theme.getName()), StandardCharsets.UTF_8); } catch (IOException e) { throw new ExecutionFailedException( "Unable to write theme import file", e); 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 ac06fd2f931..167df800ec6 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 @@ -21,14 +21,15 @@ const copyThemeResources = require('./theme-copy'); let logger; +// matches theme folder name in 'theme/my-theme/my-theme.js' +const nameRegex = /theme\/(.*)\/\1.js/g; + /** * The application theme plugin is for generating, collecting and copying of theme files for the application theme. * - * TODO: enable giving themes to handle #9383 - * * The plugin should be supplied with the paths for * - * themeJarFolder - theme folder inside a jar + * themeResourceFolder - theme folder where flow copies local and jar resource frontend files * themeProjectFolders - array of possible locations for theme folders inside the project * projectStaticAssetsOutputFolder - path to where static assets should be put */ @@ -36,13 +37,13 @@ class ApplicationThemePlugin { constructor(options) { this.options = options; - if(!this.options.themeJarFolder) { - throw new Error("Missing themeJarFolder path"); + if (!this.options.themeResourceFolder) { + throw new Error("Missing themeResourceFolder path"); } - if(!this.options.projectStaticAssetsOutputFolder) { + if (!this.options.projectStaticAssetsOutputFolder) { throw new Error("Missing projectStaticAssetsOutputFolder path"); } - if(!this.options.themeProjectFolders) { + if (!this.options.themeProjectFolders) { throw new Error("Missing themeProjectFolders path array"); } } @@ -51,17 +52,44 @@ class ApplicationThemePlugin { logger = compiler.getInfrastructureLogger("ApplicationThemePlugin"); compiler.hooks.afterEnvironment.tap("ApplicationThemePlugin", () => { - if (fs.existsSync(this.options.themeJarFolder)) { - logger.debug("Found themeFolder in jar file ", this.options.themeJarFolder); - handleThemes(this.options.themeJarFolder, this.options.projectStaticAssetsOutputFolder); - } + const generatedThemeFile = path.resolve(this.options.themeResourceFolder, "theme-generated.js"); + if (fs.existsSync(generatedThemeFile)) { + + // read theme name from the theme-generated.js as there we always mark the used theme for webpack to handle. + const themeName = nameRegex.exec(fs.readFileSync(generatedThemeFile, {encoding: 'utf8'}))[1]; + if (!themeName) { + throw new Error("Couldn't parse theme name from '" + generatedThemeFile + "'."); + } - this.options.themeProjectFolders.forEach((themeProjectFolder) => { - if (fs.existsSync(themeProjectFolder)) { - logger.debug("Found themeFolder from ", themeProjectFolder); - handleThemes(themeProjectFolder, this.options.projectStaticAssetsOutputFolder); + let themeFound = false; + for (let i = 0; i { - if (fs.statSync(path.resolve(folder, file)).isDirectory()) { - themeFolders.push(file); - } - }); - return themeFolders; -} 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 31eaccbe1b7..b6c064ed388 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 @@ -5,7 +5,7 @@ ], "repository": "vaadin/flow", "name": "@vaadin/application-theme-plugin", - "version": "0.1.0", + "version": "0.1.1", "main": "application-theme-plugin.js", "author": "Vaadin Ltd", "license": "Apache-2.0", diff --git a/flow-server/src/main/resources/webpack.generated.js b/flow-server/src/main/resources/webpack.generated.js index f33486d73cf..d7cba22e14d 100644 --- a/flow-server/src/main/resources/webpack.generated.js +++ b/flow-server/src/main/resources/webpack.generated.js @@ -193,7 +193,7 @@ module.exports = { !devMode && new CompressionPlugin(), new ApplicationThemePlugin({ - themeJarFolder: path.resolve(flowFrontendFolder, 'theme'), + themeResourceFolder: path.resolve(flowFrontendFolder, 'theme'), themeProjectFolders: themeProjectFolders, projectStaticAssetsOutputFolder: projectStaticAssetsOutputFolder, }), diff --git a/flow-tests/test-themes/frontend/theme/no-copy/no-copy.txt b/flow-tests/test-themes/frontend/theme/no-copy/no-copy.txt new file mode 100644 index 00000000000..19b79daf2a5 --- /dev/null +++ b/flow-tests/test-themes/frontend/theme/no-copy/no-copy.txt @@ -0,0 +1,2 @@ +This text file should not get copied +as only app-theme should be used in module. diff --git a/flow-tests/test-themes/pom.xml b/flow-tests/test-themes/pom.xml index 7353c6d4406..54e9df70d6e 100644 --- a/flow-tests/test-themes/pom.xml +++ b/flow-tests/test-themes/pom.xml @@ -57,6 +57,13 @@ + + + + + ${project.build.outputDirectory}/META-INF/resources + + vaadin.allow.appshell.annotations 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 513b4b01dab..5e9055a83c0 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 @@ -15,17 +15,25 @@ */ package com.vaadin.flow.uitest.ui.theme; -import java.util.List; - import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; import com.vaadin.flow.testutil.ChromeBrowserTest; -import com.vaadin.testbench.TestBenchElement; public class ThemeIT extends ChromeBrowserTest { + @Test + public void secondTheme_staticFilesNotCopied() { + getDriver().get(getRootURL() + "/theme/app-theme/img/bg.jpg"); + Assert.assertFalse("app-theme static files should be copied", + driver.getPageSource().contains("Could not navigate")); + + getDriver().get(getRootURL() + "/theme/no-copy/no-copy.txt"); + Assert.assertTrue("no-copy theme should not be handled", + driver.getPageSource().contains("Could not navigate to 'theme/no-copy/no-copy.txt'")); + } + @Test public void applicationTheme_GlobalCss_isUsed() { open(); @@ -35,6 +43,10 @@ public void applicationTheme_GlobalCss_isUsed() { Assert.assertEquals( "url(\"" + getRootURL() + "/theme/app-theme/img/bg.jpg\")", findElement(By.tagName("body")).getCssValue("background-image")); + + getDriver().get(getRootURL() + "/theme/app-theme/img/bg.jpg"); + Assert.assertFalse("app-theme background file should be served", + driver.getPageSource().contains("Could not navigate")); } @Override