Skip to content

Commit

Permalink
feat: Resource handling to not need plugin copying (#9558)
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.

part of #9410 and #9533
# Conflicts:
#	flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeUpdater.java
#	flow-server/src/main/resources/webpack.generated.js
  • Loading branch information
caalador authored and taefi committed Mar 2, 2021
1 parent 1493a65 commit 6bbd827
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ static Map<String, String> getDefaultDevDependencies() {

defaults.put("typescript", "4.0.3");
defaults.put("ts-loader", "8.0.12");
defaults.put("file-loader", "6.1.0");
defaults.put("extract-loader", "5.1.0");
defaults.put("lit-css-loader", "0.0.4");

// Constructable style sheets is only implemented for chrome,
// polyfill needed for FireFox et.al. at the moment
defaults.put("construct-style-sheets-polyfill", "2.4.2");
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 @@ -15,52 +15,13 @@
*/

/**
* This file handles copying of theme files to
* [staticResourcesFolder]
* This contains functions and features used to copy theme files.
*/

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 +79,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
25 changes: 24 additions & 1 deletion flow-server/src/main/resources/webpack.generated.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const ApplicationThemePlugin = require('@vaadin/application-theme-plugin');
const path = require('path');
const baseDir = path.resolve(__dirname);
// the folder of app resources (main.js and flow templates)

// this matches /theme/my-theme/ and is used to check css url handling and file path build.
const themePartRegex = /(\\|\/)theme\1[\s\S]*?\1/;

const frontendFolder = '[to-be-generated-by-flow]';

const fileNameOfTheFlowGeneratedMainEntryPoint = '[to-be-generated-by-flow]';
Expand Down Expand Up @@ -160,7 +164,9 @@ 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 themeResource = resourcePath.match(themePartRegex) && url.match(/^theme\/[\s\S]*?\//);
return resolve || themeResource;
},
// use theme-loader to also handle any imports in css files
importLoaders: 1
Expand All @@ -176,6 +182,23 @@ 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(resourcePath, resourceQuery) {
const urlResource = resourcePath.substring(frontendFolder.length);
if(urlResource.match(themePartRegex)){
return /^(\\|\/)theme\1[\s\S]*?\1(.*)/.exec(urlResource)[2];
}
return '[path][name].[ext]';
}
}
}],
},
]
},
performance: {
Expand Down

0 comments on commit 6bbd827

Please sign in to comment.