Skip to content

Commit

Permalink
feat: Resource handling to not need plugin copying
Browse files Browse the repository at this point in the history
Fixed the url handling so that theme resources
get prepended with theme/[themeName] while
having the correct absolute path. With this we can handle
these url resources with the css-loader which in turn
leads to file-loader gettign the files for copying.

External url are still not touched in any way.

Only negative is now we loose any folder the resources
were located at.
  • Loading branch information
caalador committed Dec 2, 2020
1 parent 079c7d2 commit 446164f
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ static Map<String, String> getDefaultDevDependencies() {
defaults.put("css-loader", "4.2.1");
defaults.put("extract-loader", "5.1.0");
defaults.put("lit-css-loader", "0.0.4");
defaults.put("file-loader", "6.1.0");
defaults.put("loader-utils", "1.4.0");
defaults.put("lit-element", "2.3.1");
defaults.put("lit-html", "1.2.1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
const fs = require('fs');
const path = require('path');
const generateThemeFile = require('./theme-generator');
const { copyThemeResources, copyStaticAssets } = require('./theme-copy');
const copyStaticAssets = require('./theme-copy');

let logger;

Expand Down Expand Up @@ -112,7 +112,6 @@ function handleThemes(themeName, themesFolder, projectStaticAssetsOutputFolder)

const themeProperties = getThemeProperties(themeFolder);

copyThemeResources(themeFolder, projectStaticAssetsOutputFolder);
copyStaticAssets(themeProperties, projectStaticAssetsOutputFolder, logger);

const themeFile = generateThemeFile(themeFolder, themeName);
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.1.6",
"version": "0.2.0",
"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 @@ -23,44 +23,6 @@ const fs = require('fs');
const path = require('path');
const glob = require('glob');

/**
* Copy theme files 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
*/
function copyThemeResources(themeFolder, projectStaticAssetsOutputFolder) {
if (!fs.existsSync(path.resolve(projectStaticAssetsOutputFolder))) {
require('mkdirp')(path.resolve(projectStaticAssetsOutputFolder));
}
copyThemeFiles(themeFolder, projectStaticAssetsOutputFolder);
}

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

/**
* 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
*/
function copyThemeFiles(folderToCopy, targetFolder) {
fs.readdirSync(folderToCopy).forEach(file => {
if (fs.statSync(path.resolve(folderToCopy, file)).isDirectory()) {
if (!fs.existsSync(path.resolve(targetFolder, file))) {
fs.mkdirSync(path.resolve(targetFolder, file));
}
copyThemeFiles(path.resolve(folderToCopy, file), path.resolve(targetFolder, file));
} else if (!ignoredFileExtensions.includes(path.extname(file))) {
fs.copyFileSync(path.resolve(folderToCopy, file), path.resolve(targetFolder, file));
}
});
}


/**
* Copy any static node_modules assets marked in theme.json to
* project static assets folder.
Expand Down Expand Up @@ -118,4 +80,4 @@ function copyStaticAssets(themeProperties, projectStaticAssetsOutputFolder, logg
});
};

module.exports = { copyThemeResources, copyStaticAssets };
module.exports = copyStaticAssets;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
],
"repository": "vaadin/flow",
"name": "@vaadin/theme-loader",
"version": "0.0.2",
"version": "0.0.3",
"main": "theme-loader.js",
"author": "Vaadin Ltd",
"license": "Apache-2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const loaderUtils = require("loader-utils");
const fs = require('fs');
const path = require('path');

// Collect groups [url(] [ |'|"]optional './', file part and end of url
// Collect groups [url(] [ |'|"]optional './|../', file part and end of url
const urlMatcher = /(url\()(\'|\")?(\.\/|\.\.\/)(\S*)(\2\))/g;

/**
Expand All @@ -21,11 +21,11 @@ module.exports = function (source, map) {
let themeFolder = handledResourceFolder;
// Recurse up until we find the theme folder or don't have 'theme' on the path.
while (themeFolder.indexOf("theme") > 1
&& path.basename(path.resolve(themeFolder, "..")) !== "theme") {
&& path.basename(path.resolve(themeFolder, "..")) !== "theme") {
themeFolder = path.resolve(themeFolder, "..");
}
// If we have found no theme folder return without doing anything.
if(path.basename(path.resolve(themeFolder, "..")) !== "theme") {
if (path.basename(path.resolve(themeFolder, "..")) !== "theme") {
this.callback(null, source, map);
return;
}
Expand All @@ -35,14 +35,15 @@ module.exports = function (source, map) {
source = source.replace(urlMatcher, function (match, url, quoteMark, replace, fileUrl, endString) {
let absolutePath = path.resolve(handledResourceFolder, replace, fileUrl);
if (fs.existsSync(absolutePath) && absolutePath.startsWith(themeFolder)) {
logger.debug("Updating url for file '", replace, fileUrl, "' to use 'VAADIN/static'");
const frontendThemeFolder = "theme/" + path.basename(themeFolder);
logger.debug("Updating url for file", "'" + replace + fileUrl + "'", "to use", "'" + frontendThemeFolder + "/" + fileUrl + "'");
const pathResolved = absolutePath.substring(themeFolder.length).replace(/\\/g, '/');

// keep the url the same except replace the ./ to VAADIN/static
// keep the url the same except replace the ./ or ../ to theme/[themeFolder]
if (quoteMark) {
return url + quoteMark + 'VAADIN/static' + pathResolved + endString;
return url + quoteMark + frontendThemeFolder + pathResolved + endString;
}
return url + 'VAADIN/static' + pathResolved + endString;
return url + frontendThemeFolder + pathResolved + endString;
} else if (options.devMode) {
logger.info("No rewrite for '", match, "' as the file was not found.");
}
Expand Down
20 changes: 19 additions & 1 deletion flow-server/src/main/resources/webpack.generated.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,14 @@ module.exports = {
options: {
url: (url, resourcePath) => {
// Only translate files from node_modules
return resourcePath.includes('/node_modules/');
const resolve = resourcePath.match(/(\\|\/)node_modules\1/);
const themResource = resourcePath.match(/(\\|\/)theme\1[\s\S]*?\1/) && url.match(/theme\/[\s\S]*?\//);
if(resolve) {
console.debug("Inlining node_module resource: ", url);
} else if(themResource) {
console.debug("Handling theme resource: ", url);
}
return resolve || themResource;
},
// use theme-loader to also handle any imports in css files
importLoaders: 1
Expand All @@ -195,6 +202,17 @@ module.exports = {
}
],
},
{
// File-loader only copies files used as imports in .js files or handled by css-loader
test: /\.(png|gif|jpg|jpeg|svg|eot|woff|woff2|ttf)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: 'static/',
name: '[name].[ext]'
}
}],
},
]
},
performance: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,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.HAND_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 All @@ -52,7 +53,7 @@ public void typeScriptCssImport_stylesAreApplied() {

@Test
public void secondTheme_staticFilesNotCopied() {
getDriver().get(getRootURL() + "/path/VAADIN/static/img/bg.jpg");
getDriver().get(getRootURL() + "/path/VAADIN/static/bg.jpg");
Assert.assertFalse("app-theme static files should be copied",
driver.getPageSource().contains("HTTP ERROR 404 Not Found"));

Expand All @@ -69,12 +70,12 @@ public void applicationTheme_GlobalCss_isUsed() {

final WebElement body = findElement(By.tagName("body"));
Assert.assertEquals(
"url(\"" + getRootURL() + "/path/VAADIN/static/img/bg.jpg\")",
"url(\"" + getRootURL() + "/path/VAADIN/static/bg.jpg\")",
body.getCssValue("background-image"));

Assert.assertEquals("Ostrich", body.getCssValue("font-family"));

getDriver().get(getRootURL() + "/path/VAADIN/static/img/bg.jpg");
getDriver().get(getRootURL() + "/path/VAADIN/static/bg.jpg");
Assert.assertFalse("app-theme background file should be served",
driver.getPageSource().contains("Could not navigate"));
}
Expand Down Expand Up @@ -105,8 +106,7 @@ public void subCssWithRelativePath_urlPathIsNotRelative() {
checkLogsForErrors();

Assert.assertEquals("Imported css file URLs should have been handled.",
"url(\"" + getRootURL()
+ "/path/VAADIN/static/icons/archive.png\")",
"url(\"" + getRootURL() + "/path/VAADIN/static/archive.png\")",
$(SpanElement.class).id(SUB_COMPONENT_ID)
.getCssValue("background-image"));
}
Expand Down

0 comments on commit 446164f

Please sign in to comment.