Skip to content

Commit

Permalink
feat: Enable importing CSS from node_modules (#9543)
Browse files Browse the repository at this point in the history
Enable using CSS files from installed node_modules by adding 'importCss' to theme/my-theme/theme.json.

Fixes #9410
  • Loading branch information
Tan Bui authored and caalador committed Mar 3, 2021
1 parent 313cd24 commit af3a276
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
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.2.1",
"version": "0.2.2",
"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 @@ -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,
Expand Down Expand Up @@ -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', '');
Expand Down
3 changes: 3 additions & 0 deletions flow-server/src/main/resources/webpack.generated.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,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]';
}
}
Expand Down
1 change: 1 addition & 0 deletions flow-tests/test-themes/frontend/theme/app-theme/theme.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"importCss": ["@fortawesome/fontawesome-free/css/all.css"],
"assets": {
"@fortawesome/fontawesome-free": {
"svgs/regular/**": "fortawesome/icons"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,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() {
Expand All @@ -50,12 +51,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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -63,6 +65,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();
Expand Down Expand Up @@ -144,4 +168,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);
}
}

0 comments on commit af3a276

Please sign in to comment.