diff --git a/src/main/groovy/com/devsoap/vaadinflow/actions/VaadinFlowPluginAction.groovy b/src/main/groovy/com/devsoap/vaadinflow/actions/VaadinFlowPluginAction.groovy index 43b8f29..61c9858 100644 --- a/src/main/groovy/com/devsoap/vaadinflow/actions/VaadinFlowPluginAction.groovy +++ b/src/main/groovy/com/devsoap/vaadinflow/actions/VaadinFlowPluginAction.groovy @@ -82,7 +82,6 @@ class VaadinFlowPluginAction extends PluginAction { project.with { tasks[PROCESS_RESOURCES].with { dependsOn(VersionCheckTask.NAME) - dependsOn(WrapCssTask.NAME) dependsOn(ConvertGroovyTemplatesToHTML.NAME) } diff --git a/src/main/groovy/com/devsoap/vaadinflow/tasks/WrapCssTask.groovy b/src/main/groovy/com/devsoap/vaadinflow/tasks/WrapCssTask.groovy index ca70148..979acde 100644 --- a/src/main/groovy/com/devsoap/vaadinflow/tasks/WrapCssTask.groovy +++ b/src/main/groovy/com/devsoap/vaadinflow/tasks/WrapCssTask.groovy @@ -19,7 +19,9 @@ package com.devsoap.vaadinflow.tasks import com.devsoap.vaadinflow.actions.JavaPluginAction import com.devsoap.vaadinflow.extensions.VaadinFlowPluginExtension +import com.devsoap.vaadinflow.util.ClassIntrospectionUtils import groovy.util.logging.Log +import io.github.classgraph.ScanResult import org.gradle.api.DefaultTask import org.gradle.api.file.FileTree import org.gradle.api.tasks.CacheableTask @@ -48,9 +50,10 @@ class WrapCssTask extends DefaultTask { static final String STYLES_TARGET_PATH = 'webapp-gen/frontend/styles' static final String CSS_REGEXP = '**/*.css' - private static final String CSS = '.css' + private static final String CSS = CSS_EXTENSION private static final String FRONTEND = 'frontend' private static final String STYLES = 'styles' + public static final String CSS_EXTENSION = '.css' @Optional @InputDirectory @@ -94,6 +97,7 @@ class WrapCssTask extends DefaultTask { WrapCssTask() { group = 'vaadin' description = 'Wraps CSS files in HTML/JS wrappers' + dependsOn('classes') } @TaskAction @@ -117,6 +121,7 @@ class WrapCssTask extends DefaultTask { } } + @Deprecated private void convertToHtml(FileTree tree) { tree.each { LOGGER.info("Wrapping $it in HTML wrapper") @@ -134,23 +139,75 @@ class WrapCssTask extends DefaultTask { } private void convertToJs(FileTree tree) { + + VaadinFlowPluginExtension vaadin = project.extensions.getByType(VaadinFlowPluginExtension) + ScanResult scan = ClassIntrospectionUtils.getAnnotationScan(project) + Map> cssImports = ClassIntrospectionUtils.findCssImports(vaadin, scan) + .collectEntries { [new File(cssSourceDir.call(), it.key).canonicalPath, it.value] } + tree.each { LOGGER.info("Wrapping $it in JS wrapper") - String content = -""" -// This is a autogenerated Javascript file for ${it.name}. Do not edit this file, it will be overwritten. -import '@polymer/polymer/lib/elements/custom-style.js'; - -const \$_documentContainer = document.createElement('template'); -\$_documentContainer.innerHTML = ``; -document.head.appendChild(\$_documentContainer.content); -""" + Map values = cssImports[it.canonicalPath] + String content = writeAutogeneratedComment(it.name) + if (!values) { + LOGGER.warning("Could not match file ${it.canonicalPath} to any @CssImport annotation.") + content += writeNoValueTemplate(it.name, it.text) + } else if (values?.target || values?.id) { + content += writeTargetOrIdValueTemplate(it.name, it.text, values) + } else { + content += writeAllValuesTemplate(it.name, it.text, values) + } + content += writeDocumentAppend() File js = new File(targetPath.call(), "${ cssSourceDir.call().relativePath(it) - CSS }.js" ) js.parentFile.mkdirs() js.text = content } } + + private static String writeNoValueTemplate(String name, String css) { + """ + const \$_documentContainer = document.createElement('custom-style'); + \$_documentContainer.setAttribute("id", "wrapped-${name - CSS_EXTENSION}"); + \$_documentContainer.innerHTML = ``; + """.stripIndent() + } + + private static String writeTargetOrIdValueTemplate(String name, String css, Map values) { + """ + const \$_documentContainer = document.createElement('dom-module'); + ${values.id ? "\$_documentContainer.setAttribute(\"id\",\"${values.id}\");" : '' } + ${values.target ? "\$_documentContainer.setAttribute(\"theme-for\",\"${values.target}\");" : '' } + \$_documentContainer.innerHTML = ``; + """.stripIndent() + } + + private static String writeAllValuesTemplate(String name, String css, Map values) { + """ + const \$_documentContainer = document.createElement('custom-style'); + \$_documentContainer.setAttribute("id", "wrapped-${name - CSS_EXTENSION}"); + \$_documentContainer.innerHTML = ` + `; + """.stripIndent() + } + + private static String writeAutogeneratedComment(String name) { + """ + // This is a autogenerated Javascript file for ${name}. Do not edit this file, it will be overwritten. + """.stripIndent() + } + + private static String writeDocumentAppend() { + """ + document.head.appendChild(\$_documentContainer); + """.stripIndent() + } } diff --git a/src/main/groovy/com/devsoap/vaadinflow/util/ClassIntrospectionUtils.groovy b/src/main/groovy/com/devsoap/vaadinflow/util/ClassIntrospectionUtils.groovy index 2bd3793..a6fbbc7 100644 --- a/src/main/groovy/com/devsoap/vaadinflow/util/ClassIntrospectionUtils.groovy +++ b/src/main/groovy/com/devsoap/vaadinflow/util/ClassIntrospectionUtils.groovy @@ -18,12 +18,14 @@ package com.devsoap.vaadinflow.util import com.devsoap.vaadinflow.extensions.VaadinFlowPluginExtension +import groovy.transform.PackageScope import groovy.util.logging.Log import io.github.classgraph.AnnotationInfo import io.github.classgraph.ClassGraph import io.github.classgraph.ClassInfo import io.github.classgraph.ClassInfoList import io.github.classgraph.ScanResult +import org.gradle.api.GradleException import org.gradle.api.Project import java.nio.file.Path @@ -218,11 +220,18 @@ class ClassIntrospectionUtils { * @return * the values of the css imports */ - static final Map findCssImportsByRoute(ScanResult scan) { - Map imports = [:] + static final Map> findCssImportsByRoute(ScanResult scan) { + Map> imports = [:] List processedClasses = [] scan.getClassesWithAnnotation(ROUTE_FQN).each { ClassInfo ci -> - findImportModulesByDependencies(ci, imports, CSS_IMPORT_FQN, processedClasses) + findImportModulesByDependencies(ci, imports, CSS_IMPORT_FQN, processedClasses) { info, a -> + [ + 'className' : info.name, + 'include' : a.parameterValues.include?.value, + 'id' : a.parameterValues.id?.value, + 'target' : a.parameterValues.themeFor?.value + ] + } } LOGGER.info("Scanned ${processedClasses.size()} classes.") imports @@ -237,16 +246,32 @@ class ClassIntrospectionUtils { * @return * the values of the css imports */ - static final Map findCssImportsByWhitelist(ScanResult scan) { - Map imports = [:] + static final Map> findCssImportsByWhitelist(ScanResult scan) { + Map> imports = [:] scan.getClassesWithAnnotation(CSS_IMPORT_FQN).collect { ClassInfo ci -> ci.getAnnotationInfoRepeatable(CSS_IMPORT_FQN).each { AnnotationInfo a -> - imports[a.parameterValues.value.value.toString()] = ci.name + imports[a.parameterValues.value.value.toString()] = [ + 'className' : ci.name, + 'include' : a.parameterValues.include?.value, + 'id' : a.parameterValues.id?.value, + 'target' : a.parameterValues.themeFor?.value + ] } } imports } + static final Map> findCssImports(VaadinFlowPluginExtension vaadin, ScanResult scan) { + switch (vaadin.scanStrategy) { + case 'route': + return findCssImportsByRoute(scan) + case 'whitelist': + return findCssImportsByWhitelist(scan) + default: + throw new GradleException("Scan strategy $vaadin.scanStrategy has not been implemented.") + } + } + /** * Find all classes which has an @Id filed annotation * @@ -269,18 +294,21 @@ class ClassIntrospectionUtils { * the annotation to search for * @param processedClasses * the accumulated processedClasses + * @param valueGenerator + * the generator that generates the returned map values */ - static final void findImportModulesByDependencies(ClassInfo info, Map imports, String annotation, - List processedClasses) { + static final void findImportModulesByDependencies(ClassInfo info, Map imports, String annotation, + List processedClasses, + Closure valueGenerator = { i, a -> i.name }) { processedClasses << info.name if (info.hasAnnotation(annotation)) { info.getAnnotationInfoRepeatable(annotation).each { AnnotationInfo a -> - imports[a.parameterValues.value.value.toString()] = info.name + imports[a.parameterValues.value.value.toString()] = valueGenerator.call(info, a) } } info.classDependencies.each { ClassInfo childInfo -> if (!processedClasses.contains(childInfo.name)) { - findImportModulesByDependencies(childInfo, imports, annotation, processedClasses) + findImportModulesByDependencies(childInfo, imports, annotation, processedClasses, valueGenerator) } } }