2015-08-28 4 views
1

СценарийSBT-веб-настройки вывода активов каталог

У меня есть довольно простой Scalatra проект с Scala.js и МЕНЬШЕ, для которого мне нужно создать конфигурацию SBT сборки. Проект разделен на три части: jvm, js, общий код.

В моей текущей конфигурации сборки используется xsbt-web-плагин для WAR-упаковки, и я бы хотел настроить sbt-web, чтобы он мог работать с обработкой источников LESS.

Этот вопрос

С текущей конфигурации, когда я запускаю команду пакета, SBT-веб ставит активы в WEB-INF/классы/основные/META-INF/ресурсы/webjars/dataretrieverjvm/0,1. 0-SNAPSHOT. Я бы хотел разместить их в WEB_INF/public, но я не могу понять, как я мог это достичь.

Это как мой Build.scala выглядит на данный момент:

import org.scalajs.sbtplugin.cross.CrossProject 
import sbt._ 
import com.earldouglas.xwp._ 
import play.twirl.sbt._ 
import org.scalajs.sbtplugin.ScalaJSPlugin 
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._ 
import com.typesafe.sbt.web._ 
import com.typesafe.sbt.web.SbtWeb.autoImport._ 
import com.typesafe.sbt.less.SbtLess.autoImport._ 

object DataRetrieverBuild extends Build { 
    private val organization  = "Foobar Ltd" 
    private val scalaVersion  = "2.11.7" 
    private val scalaBinaryVersion = "2.11" 
    private val scalatraVersion = "2.3.1" 
    private val akkaVersion  = "latest.release" 
    private val scalacOptions  = Seq(
    "-unchecked", "-deprecation", "-Yinline-warnings", "-optimise", "-target:jvm-1.8", "-Xlint", "-feature" 
) 
    private val javacOptions  = Seq(
    "-Xlint:all" 
) 
    private val jvmLibraryDependencies = Def.setting(
    Seq(
     "ch.qos.logback" % "logback-classic" % "latest.release", 
     "com.mchange" % "c3p0" % "latest.release", 
     "com.typesafe.akka" %% "akka-actor" % akkaVersion, 
     "com.typesafe.play" %% "anorm" % "latest.release", 
     "javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided", 
     "org.apache.commons" % "commons-email" % "latest.release", 
     "org.json4s" %% "json4s-jackson" % "latest.release", 
     "org.scalatra" %% "scalatra" % scalatraVersion, 
     "org.scalatra" %% "scalatra-auth" % scalatraVersion, 
     "org.slf4j" % "slf4j-api" % "latest.release", 
     "com.ibm.tools.target" % "was-liberty" % "8.5.x.3" % "provided" 
    ) 
) 
    private val jsLibraryDependencies  = Def.setting(
    Seq(
     "be.doeraene" %%% "scalajs-jquery" % "latest.release", 
     "org.scala-js" %%% "scalajs-dom" % "latest.release", 
     "org.webjars" % "bootstrap" % "3.3.5" exclude("org.webjars", "jquery") 
    ) 
) 
    private val jsWebjarDependencies  = Def.setting(
    Seq(
     "org.webjars" % "jquery" % "2.1.4"/"jquery.js" minified "jquery.min.js", 
     "org.webjars" % "underscorejs" % "1.8.3"/"underscore.js" minified "underscore-min.js", 
     "org.webjars" % "bootstrap" % "3.3.5"/"bootstrap.js" minified "bootstrap.min.js" dependsOn("jquery.js", "underscore.js", "moment.js"), 
     "org.webjars" % "ractive" % "0.7.1"/"ractive.js" minified "ractive.min.js", 
     "org.webjars" % "momentjs" % "2.10.6"/"moment.js" minified "moment.min.js" 
    ) 
) 
    private[this] val artifactPath = file(".") 
    private val autoAPIMappings = true 
    private val scalaDocOptions = Seq(
    "-implicits", "-diagrams" 
) 

    private lazy val sharedBuildSettings = Seq(
    Keys.organization         := organization, 
    Keys.name           := "DataRetrieverShared", 
    Keys.version          := "0.1.0-SNAPSHOT", 
    Keys.scalaVersion         := scalaVersion, 
    Keys.scalaBinaryVersion       := scalaBinaryVersion, 
    Keys.scalacOptions         ++= scalacOptions, 
    Keys.scalacOptions in (Compile, Keys.doc)   ++= scalaDocOptions ++ Opts.doc.title("DataRetrieverShared"), 
    Keys.javacOptions         ++= javacOptions, 
    Keys.target in (Compile, Keys.doc)     := file("jvm-api"), 
    Keys.autoAPIMappings        := autoAPIMappings 
) 

    private lazy val jvmBuildSettings = Seq(
    Keys.organization         := organization, 
    Keys.name           := "DataRetrieverJVM", 
    Keys.version          := "0.1.0-SNAPSHOT", 
    Keys.scalaVersion         := scalaVersion, 
    Keys.scalaBinaryVersion       := scalaBinaryVersion, 
    Keys.scalacOptions         ++= scalacOptions, 
    Keys.scalacOptions in (Compile, Keys.doc)   ++= scalaDocOptions ++ Opts.doc.title("DataRetrieverJVM"), 
    Keys.javacOptions         ++= javacOptions, 
    Keys.checksums in Keys.update      := Nil, 
    Keys.resolvers          ++= Seq(
     "IBM" at "http://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/maven/repository/" 
    ), 
    Keys.libraryDependencies       ++= jvmLibraryDependencies.value, 
    Keys.artifactPath in Keys.`package`    ~= { defaultPath => artifactPath/defaultPath.getName }, 
    Keys.artifactName in Keys.`package`    := { 
     (sv: ScalaVersion, module: ModuleID, artifact: Artifact) => 
     s"${artifact.name}.${artifact.extension}" 
    }, 
    WebappPlugin.autoImport.webappWebInfClasses  := true, 
    LessKeys.compress in Assets      := true, 
    WebKeys.webTarget         := Keys.target.value/"webapp"/"WEB-INF", 
    Keys.target in (Compile, Keys.doc)     := file("jvm-api"), 
    Keys.autoAPIMappings        := autoAPIMappings 
) 

    private lazy val jsBuildSettings = Seq(
    Keys.organization         := organization, 
    Keys.name           := "DataRetrieverJS", 
    Keys.version          := "0.1.0-SNAPSHOT", 
    Keys.scalaVersion         := scalaVersion, 
    Keys.scalaBinaryVersion       := scalaBinaryVersion, 
    Keys.scalacOptions         ++= scalacOptions, 
    Keys.scalacOptions in (Compile, Keys.doc)   ++= scalaDocOptions ++ Opts.doc.title("DataRetrieverJS"), 
    Keys.libraryDependencies       ++= jsLibraryDependencies.value, 
    jsDependencies          ++= jsWebjarDependencies.value, 
    Keys.skip in packageJSDependencies     := false, 
    Keys.target in (Compile, Keys.doc)     := file("js-api"), 
    Keys.autoAPIMappings        := autoAPIMappings 
) ++ (
    Seq(packageJSDependencies, fastOptJS, fullOptJS) map { packageJSKey => 
     Keys.crossTarget in(Compile, packageJSKey) := Keys.baseDirectory.value/".."/"jvm"/"src"/"main"/"webapp"/"WEB-INF"/"js" 
    } 
) 

    lazy val root = Project(
     id = "data-retriever-root", 
     base = file(".") 
).aggregate(dataRetrieverJVM, dataRetrieverJS) 

    lazy val dataRetriever = CrossProject(
    id = "data-retriever", 
    base = file("."), 
    crossType = CrossType.Full 
).settings(
    Defaults.coreDefaultSettings ++ sharedBuildSettings:_* 
).jvmSettings(
    Defaults.coreDefaultSettings ++ jvmBuildSettings:_* 
).jsSettings(
    Defaults.coreDefaultSettings ++ jsBuildSettings:_* 
) 

    lazy val dataRetrieverJS = dataRetriever.js.enablePlugins(ScalaJSPlugin) 

    lazy val dataRetrieverJVM = dataRetriever.jvm.enablePlugins(WarPlugin, SbtTwirl, SbtWeb) 
} 

Частичное решение

WebKeys.exportedAssets in Assets := SbtWeb.syncMappings(Keys.streams.value.cacheDirectory, (WebKeys.exportedMappings in Assets).value, Keys.target.value/"webapp"/"WEB-INF"/"public"), 
WebKeys.exportedMappings in Assets := (WebKeys.exportedMappings in Assets).value.map(item => item._1 -> item._2.replaceAll("""(.*(/|\\))*(.*)""", "$3")) 

Таким образом, активы копируются WEB-INF/общественности который отлично, но, к сожалению, sbt-web копирует их до WEB-INF/classes.

ответ

3

Похоже META-INF/ресурсы/webjars/dataretrieverjvm/0.1.0-SNAPSHOT путь может быть наступающем из createWebJarMappings в SBT-сети.

Что произойдет, если вы выберете его?

WebKeys.exportedMappings in Assets := 
    (WebKeys.exportedMappings in Assets).value map { case (file, string) => 
    import org.webjars.WebJarAssetLocator.WEBJARS_PATH_PREFIX 
    val prefix = s"${WEBJARS_PATH_PREFIX}/${moduleName.value}/${version.value}/" 
    (file, string.replace(prefix, "")) 
    } 
+0

Да, я уже нашел этот фрагмент кода. Я проверю это завтра. Надеюсь, я смогу отключить эту функцию, не открывая плагин. Кажется, я мог просто пропустить этот шаг. Я предлагаю обратное совместимое решение, если оно не выполнимо. Посмотрим. – Athelionas

+0

@Athelionas, вы уже добавили возможность отключить эту функцию? Или я должен использовать код Джеймса, чтобы избежать размещения моих ресурсов и веб-ресурсов внутри папки WEB-INF? Желательно ли размещать ресурсы, принадлежащие самому проекту внутри специальной папки META-INF? Насколько мне известно, эта папка должна содержать только информацию ** о проекте (создателе, зависимостях, поставщиках услуг и т. Д.), А не части проекта. – Readren

+0

Кроме того.Досадно знать версию проекта, чтобы иметь возможность читать веб-ресурсы из кода проекта (с помощью класса ClassLoader # getResource (String) '). – Readren

0

Можно использовать org.webjars.WebJarAssetLocator, который помогает решить частичные пути в полные пути в webjars. Вот как это работает: с учетом ссылки на странице HTML, например <script src="/js/bootstrap.min.js"></script>, сервлет может быть настроен для разрешения путей по пути к классам.

Пример менеджера ресурсов для Undertow:

public class WebLocatorWithClassPathFallbackResourceManager extends ClassPathResourceManager { 
    private WebJarAssetLocator webJarAssetLocator = new WebJarAssetLocator(); 

    public WebLocatorWithClassPathFallbackResourceManager(ClassLoader classLoader) { 
     super(classLoader); 
    } 

    @Override 
    public Resource getResource(String resourcePath) throws IOException { 
     try { 
      return super.getResource(webJarAssetLocator.getFullPath(resourcePath)); 
     } catch (MultipleMatchesException|IllegalArgumentException e) { 
      // handle mismatch 
     } 
     return super.getResource(resourcePath); 
    } 
} 

Тогда можно было бы разместить сервлет для обработки "/*" отображения и просто служить ресурсы от этого пути к классам. Предполагается, что ваши ресурсы находятся в /META-INF/resources, который доступен для Servlet 3.0+.

Смежные вопросы