Giter VIP home page Giter VIP logo

sbt-web's Introduction

sbt-web

Build Status

This project provides the building blocks for web oriented sbt plugins by bringing together the following concerns:

  • File directory layout conventions for resources intended to be served by a web server (otherwise known as assets)
  • Incremental execution of fine-grained operations within sbt tasks
  • Utilities for managing WebJars including the ability to extract a WebJar's contents on to disk
  • Standardised reporting of compilation style errors

sbt-web was driven from the desire to factor out client-side web concerns from the Play Framework. However, sbt-web is entirely independent of Play and can be used for any project that uses sbt as its build system.

Available Plugins

The following is a list of plugins we know of that are built on sbt-web:

Ideas for Plugins

Plugins in Development

  • C'mon community, get involved! Watch the talk on the anatomy of an sbt-web plugin

File Directory Layout

The following directory layout is declared by sbt-web with an indication of the associated settings:

+ src
--+ main
----+ assets .....(Assets / sourceDirectory)
------+ js
----+ public .....(Assets / resourceDirectory)
------+ css
------+ images
------+ js
--+ test
----+ assets .....(TestAssets / sourceDirectory)
------+ js
----+ public .....(TestAssets / resourceDirectory)
------+ css
------+ images
------+ js

+ target
--+ web ............(webTarget)
----+ public
------+ main .......(Assets / resourceManaged)
--------+ css
--------+ images
--------+ js
------+ test .......(TestAssets / resourceManaged)
--------+ css
--------+ images
--------+ js
----+ stage ........(stagingDirectory)

The plugin introduces the notion of assets to sbt. Assets are public resources that are intended for client-side consumption e.g. by a browser. This is also distinct from sbt's existing notion of resources as project resources are generally not made public by a web server.

In sbt, asset source files are considered the source for plugins that process them. When they are processed any resultant files go into a public directory in the classpath. By configuration, sbt-web apps serve static assets from the public directory on the classpath. For example a CoffeeScript plugin would use files from Assets / sourceDirectory and produce them to Assets / resourceManaged.

All assets whether they need processing or are static in nature, will be copied to the resourceManaged destinations.

Assets can be organized however desired within the assets directory.

One last thing regarding the public and public-test folders... any WebJar depended on by the project will be automatically extracted into these folders e.g. target/web/public/main/lib/jquery/jquery.js. In addition, the public-test folder receives the contents of the public folder as well as test assets. This eases the support of test frameworks given that all files are locatable from one root.

The "stage" directory is product of processing the asset pipeline and results in files prepared for deployment to a web server.

Configurations

sbt holds the notion of configurations which are similar to Maven's phases. Configurations aggregate settings and tasks. Familiar configurations will be Compile and Test. sbt-web introduces two new configurations named Assets and TestAssets correlating roughly with Compile and Test, but for web assets.

Incremental Execution

The incremental task API lets tasks run more quickly when they are called more than once. The idea is to do less work when tasks are called a second time, by skipping any work that has already been done. In other words, tasks only perform the "incremental" work that is necessary since they were last run.

To analyse which work needs to be done, a task's work is broken up into a number of sub-operations, each of which can be run independently. Each operation takes input parameters and can read and write files. The incremental task API keeps a record of which operations have been run so that those operations don't need to be repeated in the future.

Asset Pipeline

There are two categories of sbt-web based tasks:

  • those that operate on source files
  • those that operate on web assets

Examples of source file tasks as plugins are CoffeeScript, LESS and JSHint. Some of these take a source file and produce a target web asset e.g. CoffeeScript produces JS files. Plugins in this category are mutually exclusive to each other in terms of their function i.e. only one CoffeeScript plugin will take CoffeeScript sources and produce target JS files. In summary, source file plugins produce web assets.

Asset tasks operate on web assets directly. The assets they operate on depend on a "stage" in the asset pipeline. Examples of web asset tasks as plugins include RequireJs optimisation, gzip and md5 hashing.

Source file tasks can be considered to provide files for the first stage of asset pipeline processing and they will be executed often e.g. for each compilation of your project's source files. Asset pipeline tasks are generally executed at the time that you wish to prepare a distribution for deployment into, say, production.

Exporting Assets

Assets are automatically available across subproject dependencies using sbt's classpath setup. The assets are exported in the webjar format and are imported in the same way as other webjar dependencies.

So given a project dependency like this, where project A depends on project B:

lazy val a = (project in file("a"))
  .enablePlugins(SbtWeb)
  .dependsOn(b)

lazy val b = (project in file("b"))
  .enablePlugins(SbtWeb)

Assets from project B are available to project A under lib/b/.

The module name for imported assets is the same as the project module name (the normalized name of the project). This can be changed with the Assets / moduleName setting.

Test assets are also exported if a test dependency is specified. For example:

lazy val a = (project in file("a"))
  .enablePlugins(SbtWeb)
  .dependsOn(b % "compile;test->test")

Packaging and Publishing

The packaging and publishing behavior is documented for sbt-web version 1.1.0 and above.

Assets are automatically packaged and published along with project classes at the following path inside the jar: META-INF/resources/webjars/module/version/. This means that assets can be shared as external library dependencies. Simply publish the project and use as a library dependency. The assets will be extracted and available under lib/module/ in the same way as other webjar dependencies or internal dependencies.

To package all assets for production there is a Assets / packageBin task, web-assets:package in the sbt shell. This packages the result of the asset pipeline. An optional path prefix can be specified with the packagePrefix in Assets setting. For example, to have assets packaged under a public directory, as used for Play Framework distributions:

Assets / WebKeys.packagePrefix := "public/"

To automatically add the production-ready assets to classpath, the following might be useful:

(Runtime / managedClasspath) += (Assets / packageBin).value

Writing a Source File task

The following represents the minimum amount of code required in a build.sbt to create a task that operates on source files i.e. those files that are available for processing from src/main/assets. Source file tasks are resource generators in sbt terms.

val mySourceFileTask = taskKey[Seq[File]]("Some source file task")

mySourceFileTask := Nil

Assets / sourceGenerators += mySourceFileTask.taskValue

The addition of the mySourceFileTask to Assets / sourceGenerators declares the task as a resource generator and, as such, will be executed in parallel with other resource generators during the WebKeys.assets task execution. Using sbt's show command will yield the directory where all source file assets have been written to e.g.:

show web-assets:assets

Source file tasks take input, typically from Assets / sourceDirectory (and/or TestAssets) and produce a sequence of files that have been generated from that input.

The following code illustrates a more complete example where input files matching *.coffee are taken and copied to an output folder:

mySourceFileTask := {
  // translate .coffee files into .js files
  val sourceDir = (Assets / sourceDirectory).value
  val targetDir = webTarget.value / "cs-plugin"
  val sources = sourceDir ** "*.coffee"
  val mappings = sources pair relativeTo(sourceDir)
  val renamed = mappings map { case (file, path) => file -> path.replaceAll("coffee", "js") }
  val copies = renamed map { case (file, path) => file -> (Assets / resourceManaged).value / path }
  IO.copy(copies)
  copies map (_._2)
}

Using the WebKeys.assets task will perform source file tasks in parallel. If you find yourself using a source file task across many projects then consider wrapping it with an sbt plugin. Example source file plugins are sbt-jshint, sbt-coffeescript and sbt-stylus.

As a final note, if you plugin depends on node modules e.g. those that are extracted from WebJars or from NPM, then you will need to have your task depend on the node module extraction task. The following illustrates how given the Assets scope:

mySourceFileTask := Def.task {
  Nil
}.dependsOn(Assets / WebKeys.nodeModules).value

If you're wrapping the task within a plugin then you will need the Plugin's scope as opposed to the Assets scope i.e.:

mySourceFileTask := Def.task {
  Nil
}.dependsOn(Plugin / WebKeys.nodeModules).value

Writing an Asset Pipeline task

The following represents the minimum amount of code required to create a pipeline stage in a build.sbt file:

import com.typesafe.sbt.web.pipeline.Pipeline

val myPipelineTask = taskKey[Pipeline.Stage]("Some pipeline task")

myPipelineTask := identity

pipelineStages := Seq(myPipelineTask)

myPipelineTask is a function that receives a Seq[PathMapping] and produces a Seq[PathMapping]. PathMapping is a tuple of (File, String) where the first member provides the full path to a file, and the second member declares the portion of that path which is to be considered relative. For example (file("/a/b/c"), "b/c"). PathMapping` types are commonly used in sbt and are useful in terms of providing access to a file and preserving information about its relative path; the latter being typically useful for copying files to a target folder where the relative portion of the path must be retained.

In the above example an identity function is used i.e. what is passed in is simply returned. The task is included within a sequence and assigned to pipelineStages i.e. the sequence represents the asset pipeline. Each stage in the asset pipeline is executed after any previous stage has completed. A stage therefore receives the product of files any previous stage as input. A stage's output then becomes the input to any subsequent stage. The first stage will always receive the output of having executed source file tasks as its input.

If you have some need for the assets produced by the pipelineStages in your development environment (during play run), then you can scope the pipelineStages to the Assets config.

Assets / pipelineStages := Seq(myPipelineTask)

To perform the asset pipeline tasks use the WebKeys.stage task. If you use sbt's show command from the console then you will see the directory that the pipeline has been written to e.g.:

show web-stage

Returning what is passed in is not particularly useful. Stages tend to add and remove files from the input as expressed in the output returned. The following expanded task simulates minifying some js files and consequently adds files to the pipeline:

myPipelineTask := { mappings: Seq[PathMapping] =>
  // pretend to combine all .js files into one .min.js file
  val targetDir = webTarget.value / "myPipelineTask" / "target"
  val (js, other) = mappings partition (_._2.endsWith(".js"))
  val minFile = targetDir / "js" / "all.min.js"
  IO.touch(minFile)
  val minMappings = Seq(minFile) pair relativeTo(targetDir)
  minMappings ++ other
}

If you find yourself commonly using a pipeline stage task across projects then you should consider wrapping it with an sbt plugin. Examples of such plugins are sbt-digest, sbt-gzip, sbt-rjs and sbt-uglify. The first two illustrate stages implemented using JVM based libraries while the latter two illustrate invoking JavaScript via js-engine.

WebDriver and js-engine

The WebDriver and js-engine projects build on sbt-web and provide a DOM oriented and DOM-less means of JavaScript execution respectively. sbt-web plugins will use one of the two of these plugins depending on their DOM requirements.

Releasing sbt-web

  1. Tag the release: git tag -s 1.2.3
  2. Push tag: git push upstream 1.2.3
  3. GitHub action workflow does the rest: https://github.com/sbt/sbt-web/actions/workflows/publish.yml

sbt-web's People

Contributors

atry avatar benmccann avatar damiya avatar earldouglas avatar ebruchez avatar eed3si9n avatar gmethvin avatar guersam avatar huntc avatar jaceklaskowski avatar jamesward avatar jasonstoltz avatar jmparsons avatar john-bernardo1 avatar joost-de-vries avatar jroper avatar kolloch avatar marcospereira avatar matthewrennie avatar mdedetrich avatar mkurz avatar nafg avatar pvlugter avatar richdougherty avatar scala-steward avatar stanch avatar tanin47 avatar tindzk avatar vmunier avatar xuwei-k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sbt-web's Issues

How to use sbt-web to extract some files from a WebJars dependency to a custom output directory ?

I'm writing an experimental mobile application with scala.js and the Ionic framework (see https://github.com/olivergg/scalajs-ionic-starttabs).
My project currently depends on the ionic webjar for the javascript dependencies (using jsDependencies, an sbt key defined by scala.js). Thanks to scala.js, the javascript dependencies are automatically copied. I would like to do the same thing for the other files (fonts, css, etc.).

I've tried the following (as documented in the sbt-web homepage)

// root is the root project defined in the build.sbt
root.enablePlugins(SbtWeb)

 libraryDependencies ++= Seq(
    // ...
    "org.webjars" % "ionic" % "1.0.0-beta.13"
)

val myPipelineTask = taskKey[Pipeline.Stage]("Some pipeline task")

myPipelineTask := {
    identity
}
pipelineStages := Seq(myPipelineTask)

but I don't know what should I do from here....

Thanks.

Disable copying everything from assets folder to public folder

It seems that this plugin is copying everything from the app/assets folder to the public folder by default -- behavior that we do not desire. What is the best way to disable it entirely? Basically we only want files that reside in the public folder to end up in the class path, we will manage what goes there ourselves. Obviously I can do something like:

sourceDirectory in Assets := (sourceDirectory in Compile).value / "invalid"

But that doesn't seem very graceful...

resourceManaged vs public

The documentation says that resourceManaged in Assets corresponds to target/web/public, while in reality it corresponds to target/web/resources-managed/main.

There is also public in Assets that in turn corresponds to target/web/public and is describe in the source as what we should use to generate files to:

"public" denotes a type of asset that does not require processing i.e. these resources are static in nature.
In sbt, asset source files are considered the source for plugins that process them. When they are processed any resultant
files become public. For example a coffeescript plugin would use files from "unmanagedSources in Assets" and produce them to
"public in Assets".

So I'm a little confused whether to generate my files into resourceManaged or public.

Bug - copyResources flattens source directories into the target directory

Given a directory structure like:

  • E:\Projects\legendary\public\index.html
  • E:\Projects\legendary\public\styles
  • E:\Projects\legendary\public\styles\flex.css
  • E:\Projects\legendary\public\styles\landingPage.css
  • E:\Projects\legendary\public\styles\main.css

Executing copyResources (via a play project) will result in the following structure (erroneously moved files marked in bold)

  • E:\Projects\legendary\target\scala-2.10\classes\public\index.html
  • E:\Projects\legendary\target\scala-2.10\classes\public\styles
  • E:\Projects\legendary\target\scala-2.10\classes\public\styles\flex.css
  • E:\Projects\legendary\target\scala-2.10\classes\public\styles\landingPage.css
  • E:\Projects\legendary\target\scala-2.10\classes\public\styles\main.css
  • E:\Projects\legendary\target\scala-2.10\classes\public\flex.css
  • E:\Projects\legendary\target\scala-2.10\classes\public\landingPage.css
  • E:\Projects\legendary\target\scala-2.10\classes\public\main.css

In addition to copying files repeatedly, it also causes overwrites if a given filename exists in multiple subdirectories (such as an index.html) due to the way IO.copy's default copy impl functions.

Webjar extraction conflict

Hello,

I tried to use sbt-less-plugin in on of our projects to generate stylesheets based on bootstrap.

Unfortunately, I have both bootstrap and font-awesome in my webjars dependencies; and both contains a less/mixins.less file. This result in a file conflict and the font-awesome file takes precedence over the bootstrap one.

So, I ended up filtering the webjar extraction with the following code:

  val webJarsBuildDependencies = Seq(
      "org.webjars"       %       "bootstrap"               % "3.1.1"
  ) 

  val BuildSettings = Seq(
      WebKeys.webJarsClassLoader in WebKeys.Assets <<= (dependencyClasspath in Compile).map{
        modules => {
          val mods = for {
            mod <- modules
            attr <- mod.get(moduleID.key) if webJarsBuildDependencies contains attr
          } yield mod
          new URLClassLoader(mods.map(_.data.toURI.toURL), null)
        }
      }

  )

I think there should be a more convenient way to avoid those file conflicts, either by extracting files to different folders or by giving a simple way to filter which webjars to extract (for example based on the moduleID).

Plugins that depend on modules from NPM

For plugins that depend on modules loaded from NPM, the documentation mentions setting a dependency on the node modules extraction task but does not mention how to use a package.json file to specify the dependencies.

Does an sbt-web plugin need to include a package.json file or should its npm dependencies be specified in the package.json file of the project that declares the plugin?

Source file task running after webjars download

I'm attempting to write a source file task to compile SASS files with a library for the grid framework Susy, included in the project as a Webjar. Here's what my task looks like

lazy val sassTask = TaskKey[Seq[java.io.File]]("sassTask", "Compiles Sass files")

sassTask := {
  import sys.process._
  val sourceDir = (sourceDirectory in Assets).value
  val targetDir = (resourceManaged in Assets).value / "styles"
  Seq("scripts/sass_update.sh", "-I", "target/web/public/main/lib/susy/sass", "--update", s"$sourceDir:$targetDir").!
  Seq.empty
}

sourceGenerators in Assets <+= sassTask

The problem I'm running into is that when I clean and then compile, sassTask runs before the Susy webjar is deployed, and the compilation fails. How can I fix this?

Also, the docs are not totally clear on what's done with the Seq[File] returned by the task, so I didn't really set it intelligently. I could use some advice there. Thanks

Cache gets not cleaned after an error

The following pipeline produces an error:

Seq(gzip, digest, gzip)
[trace] Stack trace suppressed: run last *:webPipeline for the full output.
[error] (*:webPipeline) java.io.FileNotFoundException: ...

Now if I change the pipeline to Seq(rjs, digest, gzip) and run the start command again, then it shows the same error. The clean command doesn't help here. It seems that sbt-web caches operations in memory. Then all works as expected, if I terminate activator and restart it again.

It would be nice if the cache gets cleaned after an error.

composing source maps

It would be great if the source map for the products of the last stage in the asset pipeline pointed back to the original source files of the first stage. This is not what I'm seeing in play-2.3-highlights activator project. When running in production mode, main.js.map points to the javascript files generated from original coffescripts. That's quite useful, but it would be event better if would point to the original coffescript sources. Individual source maps for those generated javascript files are available and work well in development mode.

I'm not familiar with sourcemaps technical details but if each source map is a total function over output file contents, it should be technically feasible to compose those functions to arrive at a function that maps the end result of the pipeline to the original input files.

Document sbt-web

I'm having an incredibly difficult time with sbt-web. There's a couple videos online, but they only have a few minutes towards the very end about actually creating an SBT plugin and have very little detail about interfacing with SBT for someone who doesn't already know SBT very well. Also they depend on a JS plugin that's built on sbt-web, which is a confusing place to start for someone wanting to learn how to build on sbt-web.

Some things that would be helpful:

  • Is there a formula to implementing that you can always follow? Which plugins are good examples? Are some of the plugins listed bad examples because they have done things in a non-standard way?
    • e.g. Why does sbt-purescript add itself to resourceGenerators but the other plugins don't?
  • Is there anything different about implementing source file and web asset plugins or are they exactly the same except for the name?
  • Do you need to override projectSettings? Is includeFilter applicable to every plugin? Do you need to use inTask? Some plugins create a JSON object or case class which hold all the settings - what's happening and is this required or when is it helpful? What is Pipeline.Stage? What is AllRequirements?
  • At what stage of the build process will your plugin be triggered?
  • How do you make one plugin depend on another for code reuse? How do you make one plugin depend on another such that plugin A is executed first and then plugin B is executed.
  • How do you create one version of a web asset when running in development mode, but a different minimized version of that asset when running in production mode (e.g. .min.js)?

Exchange information between modules

I have a use case where the rjs module needs information from the digest module.

For RequireJS it isn't necessary to pack all modules into one file. In my app as example I use lazy loading for some modules. The problem is now that RequireJS isn't aware of the files created with the digest module and it ends up loading the non fingerprinted files.

If the rjs module knows the fingerprinted files, it could override the paths config with this files.

Original config:

require.config({
    paths: {
        'jquery': 'lib/jquery-1.11.1'
    }
});

Overriden config:

require.config({
    paths: {
        'jquery': 'lib/b028a81918e6cdde3dac41bfa72cf40b-jquery-1.11.1',
        'app/main': 'app/58a15b92be05e9baa3bd9d2ac3b378f7-main',
        ...
    }
});

Maybe this can be done with a preprocessor phase. So in this phase the diggest module creates a map for already existing files. Now this map is available to other modules so the rjs module could rewrite the RequireJS config based on this map.

In the pipeline phase the rjs module can do its normal job and the diggest module should determine if new files were created by another module and then merge the existing with the created files. At the end it should create the fingerprinted files.

So a build.sbt could be defined as follow:

preprocessorStages := Seq(digest, rjs)

pipelineStages := Seq(rjs, digest, gzip)

What do you you think? Maybe there are other methods to solve this problem.

Path issues

I've setup a simple project with the latest RC builds of sbt-web for Play 2.3, and am experiencing path issues with RequireJS during staging. It happens when a webjar has a hanging number. In my case I'm using "org.webjars" % "backbonejs" % "1.1.2-2".

When the pipeline rjs finishes, the cdn url reverts to the 1.1.2 folder instead of the 1.1.2-2.

No RequireJS Optimization or Asset Digest When Using SBT Native Packager

When configuring the project as a Java server (using packageArchtype.java_server) with Native Packager, the SBT Web pipeline doesn't complete. I'm unable to determine if this bug is with Digest, RequireJS, Web, Native Packager, or Play Framework, but this seemed the most logical place to file the report.

Steps to reproduce both cases are simple (using my sample project at https://github.com/michaelahlers/sbt-web-issue-90).

For the nominal case:

  1. Run sbt ";clean;start"
  2. See various optimization log messages (i.e., Uglify2).
  3. See versioned asset paths in page source from http://localhost:9000/.

For the failure case:

  1. Uncomment packageArchetype.java_server in build.sbt.
  2. Run sbt ";clean;start"
  3. Optimization log messages (i.e., Uglify2) are missing.
  4. Asset paths in page source from http://localhost:9000/ are not versioned.

Implementing packaging

The current thinking is that packageBin in Assets should produce a zip fit for CDN deployment and a WebJar. The zip would be the output of the assets pipeline, while the WebJar would be the result of assets minus any web modules.

Webjar locator throws IllegalStateException when adding sbt-web to the project

If I add sbt-web to my project which uses webjars then the webjar-locator throws the following exception:

Caused by: java.lang.IllegalStateException: Got deeper than 5 levels while searching /home/christian/projects/my.project/target/web/classes/main/META-INF/resources/webjars
    at org.webjars.urlprotocols.FileUrlProtocolHandler.aggregateChildren(FileUrlProtocolHandler.java:43)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.aggregateChildren(FileUrlProtocolHandler.java:47)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.aggregateChildren(FileUrlProtocolHandler.java:47)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.aggregateChildren(FileUrlProtocolHandler.java:47)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.aggregateChildren(FileUrlProtocolHandler.java:47)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.aggregateChildren(FileUrlProtocolHandler.java:47)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.aggregateChildren(FileUrlProtocolHandler.java:47)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.listFiles(FileUrlProtocolHandler.java:36)
    at org.webjars.urlprotocols.FileUrlProtocolHandler.getAssetPaths(FileUrlProtocolHandler.java:25)
    at org.webjars.WebJarAssetLocator.getAssetPaths(WebJarAssetLocator.java:80)
    at org.webjars.WebJarAssetLocator.getFullPathIndex(WebJarAssetLocator.java:106)
    at controllers.WebJarAssets.<init>(WebJarAssets.scala:26)
    at controllers.WebJarAssets$.<init>(WebJarAssets.scala:66)
    at controllers.WebJarAssets$.<clinit>(WebJarAssets.scala)

This issue occurs only during controller testing if the directory structure of the assets has a nesting level deeper than 5.

I've created a small project which reproduces the issue: https://github.com/akkie/webjar-bug

Using processed sbt-web assets in multi-module play project

I have a multi-module project. My play project (let's name it A project) is just frontend for displaing some assets in the html page. Project A depends on Project B. Project B is sbt-web project (not play, just sbt-web). In project B I have sbt-web tasks for processing my assets. This tasks produce a few files, for example app.js and app.css. How can I use this files in Project A? In target directory of Project A I can find only original assets, not processed. For now I can find processed files only in target/web/stage directory of Project B.

Add sbt-jasmine

For angular.js apps it would be great to have an sbt-jasmine plugin. Are there plans to add this?

Add support for typescript

Play 2.3 is incompatible with typescript plugin [https://github.com/mumoshu/play2-typescript], sbt-web plugin is really anticipated

sbt-uglify 1.0.1 broken on Windows

When running activator start, I get this:

java.lang.StringIndexOutOfBoundsException: String index out of range: 1
        at java.lang.String.charAt(String.java:658)
        at java.util.regex.Matcher.appendReplacement(Matcher.java:762)
        at java.util.regex.Matcher.replaceAll(Matcher.java:906)
        at java.lang.String.replaceAll(String.java:2162)
        at com.typesafe.sbt.uglify.SbtUglify$$anonfun$runOptimizer$1$$anonfun$apply$3$$anonfun$3.apply(SbtUglify.scala:97)
        at com.typesafe.sbt.uglify.SbtUglify$$anonfun$runOptimizer$1$$anonfun$apply$3$$anonfun$3.apply(SbtUglify.scala:94)
        at sbt.FileFunction$$anonfun$cached$1.apply(Tracked.scala:188)
        at sbt.FileFunction$$anonfun$cached$1.apply(Tracked.scala:188)
        at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3$$anonfun$apply$4.apply(Tracked.scala:202)
        at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3$$anonfun$apply$4.apply(Tracked.scala:198)
        at sbt.Difference.apply(Tracked.scala:177)
        at sbt.Difference.apply(Tracked.scala:158)
        at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3.apply(Tracked.scala:198)
        at sbt.FileFunction$$anonfun$cached$2$$anonfun$apply$3.apply(Tracked.scala:197)
        at sbt.Difference.apply(Tracked.scala:177)
        at sbt.Difference.apply(Tracked.scala:152)
        at sbt.FileFunction$$anonfun$cached$2.apply(Tracked.scala:197)
        at sbt.FileFunction$$anonfun$cached$2.apply(Tracked.scala:195)
        at com.typesafe.sbt.uglify.SbtUglify$$anonfun$runOptimizer$1$$anonfun$apply$3.apply(SbtUglify.scala:161)
        at com.typesafe.sbt.uglify.SbtUglify$$anonfun$runOptimizer$1$$anonfun$apply$3.apply(SbtUglify.scala:78)
        at scala.Function$$anonfun$chain$1$$anonfun$apply$1.apply(Function.scala:24)
        at scala.Function$$anonfun$chain$1$$anonfun$apply$1.apply(Function.scala:24)
        at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:111)
        at scala.collection.immutable.List.foldLeft(List.scala:84)
        at scala.collection.TraversableOnce$class.$div$colon(TraversableOnce.scala:138)
        at scala.collection.AbstractTraversable.$div$colon(Traversable.scala:105)
        at scala.Function$$anonfun$chain$1.apply(Function.scala:24)
        at com.typesafe.sbt.web.SbtWeb$$anonfun$projectSettings$36.apply(SbtWeb.scala:208)
        at com.typesafe.sbt.web.SbtWeb$$anonfun$projectSettings$36.apply(SbtWeb.scala:208)
        at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
        at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
        at sbt.std.Transform$$anon$4.work(System.scala:64)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
        at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
        at sbt.Execute.work(Execute.scala:244)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
        at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
        at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
[error] (*:webPipeline) java.lang.StringIndexOutOfBoundsException: String index
out of range: 1

Could be another forward/backward slash path issue...

Using WebJar artifactId for directory can cause issues

We currently have an issue where the WebJar for angular has the artifactId of "angularjs". However, both npm and bower have the artifactId of "angular". Also, the require module is "angular". This can cause issues with projects that are trying to use both WebJars and npm and/or bower. For more details, see the issue originally filed against WebJars here:

webjars/webjars#485

sbt-web should not honour Typesafe config system properties

See playframework/playframework#3106.

In Play, you override the typesafe-config file in dev mode by doing:

activator -Dconfig.file=path/to/my/file.conf run

The problem is, sbt-web is honouring this system property too, and so is using a config file design for Play. sbt-web should not do this, rather, it should use properties such as sbt.web.config.file. I realise the logic that does this is probably in typesafe-config.

Implementation of Handlebar Plugin

Hi guys
I used the mustache plugin for the Play Framework (https://github.com/julienba/play2-mustache) pretty extensively during the last 1.5 years. Unfortunately the developer finally quit migrating his plugin to the newest Play version 2.3 as he is moving away from Play and Scala and declared his plugin as deprecated instead. I am completely stuck since I migrated the whole project to Play 2.3. I now realized that my mustache templates are fully compatible to the handlebar library and saw, that an sbt-handlebar plugin is declared as an idea. Are there any concrete plans to implement such a plugin? It's currently really frustrating as I am completely stuck! :-(

Doc suggestion: Why Assets configuration scope?

I tried reading the SBT documentation about scopes and it mentions things like Compile, Test, and Runtime. These scopes come from Maven/Ivy and I understand why you'd have different dependencies during compilation, testing, and runtime. I don't understand Assets as a configuration scope though because it seems like it's being used in a very different context.

Is Assets just for namespacing the configuration keys or is it serving another purpose?

it:test (IntegrationTest) does not see (does not compile?) sbt-web managed sources

after upgrade to 2.3.0 from 2.1.3 we received 404s on our LESS-compiled files, while sbt run and stage yield proper results, FakeApplication in our selenium harnesses do not see the resources.

if we somehow succeed to state that it:test depends on web-assets:assets - will this help? Do we need to do any extra classloader/resourceloader configurations for this case?

Comparing sbt-web with grunt for SPAs

This is more of an observation than an issue.

I am starting development on a new SaaS product and the chosen stack is angular front-end + play rest backend. This seems to be an increasingly popular choice.

Initially I wanted to use grunt for the front-end but am now intrigued by the promise of sbt-web as I would also like to keep my development stack simple and integrated.
However I would like to retain all the development productivity and runtime efficiency that a grunt based solution would offer.

To compare the solutions, I took the list of popular grunt plugins and tried to check the equivalent solution in sbt-web/play

Grunt Description sbt-web
jshint Validate files with JsHint sbt-jshint
watch Run predefined tasks whenever watched file patterns are added, changed or deleted sbt + Play auto refresh
uglify Minify files with UglifyJs sbt-uglify, sbt-rjs
clean Clean files and folders sbt
copy Copy files and folders. sbt / sbt-web
concat Concatenate files sbt-rjs
cssmin Compress Css files. sbt-less - only for less files
connect Start a connect web server. N.A
karma karma test runner -
less Compile Less files to Css. sbt-less
coffee Compile Coffeescript files to Javascript sbt-coffeescript
concurrent Run grunt tasks concurrently sbt
imagemin Minify PNG, JPEG and GIF images -
compass Compile sass to Css using Compass -
usemin Replaces references to non-optimized scripts or stylesheets into a set of HTML files [or any templates/views] sbt-rjs
htmlmin Minify HTML -
requirejs Optimize RequireJs projects using r.js. sbt-rjs
rev static file asset revisioning through content hashing sbt-digest
autoprefixr Parse CSS and add vendor-prefixed CSS properties using the Can I Use database -
shell Run Shell Commands sbt
svgmin Minify SVG -

In addition, the following is my subjective selection of items which are a little lower in the list (sorted by popularity)

Grunt Description sbt-web
newer Run Grunt tasks with only those source files modified since the last successful run sbt / sbt-web
mocha Grunt task for running client-side Mocha specs in PhantomJs sbt-mocha-plugin
jasmine Run jasmine specs headlessly through PhantomJs -
angular-templates Grunt build task to concatenate & register your AngularJs templates in the $templateCache -
protractor-runner A Grunt plugin for running protractor runner. -
ngmin Grunt task for minifying AngularJS projects -

I am pleasantly surprised with the coverage present already. I understand that the priority is to have feature-parity with Play 2.2 asset capabilities but it will be great if we tick the missing boxes over time (probably by the community)

It will be good if we can have a documentation page - sbt-web for grunt users

Changes to static files trigger RELOAD

With a play 2.2 application it was possible to change a static file (in public/) and see the changes (after F5 or s.th. similar) without a reload of the application. Static files might be e.g. templates/partials of an angular.js application or regular js files (in public).

With 2.3 / sbt-web this is no longer the case - changing a static file triggers a reload of the application.

To reproduce this:

Now the console shows that another --- (RELOAD) --- was done. This was not the case with play 2.2.1 (to be sure I also checked this with a previous version of angular-seed-play).

Although play apps should reload fast, this is not always the case (or possible). Even if reload takes only 5 or 10 seconds this is rather annoying when working on frontend stuff.

Is it possible to change this, so that static files do not trigger an application reload?

Integrating with Spray+sbt-revolver workflow

Hi,

What’s the best way to integrate sbt-web with Spray and sbt-revolver? I have enabled sbt-web with enablePlugins(SbtWeb). The project compiles, however I’m not sure about two things:

  • The ~re-start command from sbt-revolver does not trigger asset (re)compilation. The latter runs only if I touch show web-assets:assets explicitly from the sbt console. How do I set this up?
  • The processed assets are put into target/web/public/main. Should I serve them from there in production, or they are meant to be packaged in some way?

Nick

Multi module projects

Devise a strategy and implementation for handling assets within a multi-project build. Play has a strategy that we should adopt, and that Play can subsequently benefit from also.

@pvlugter

sbt package will ignore sbt-web

Typing 'sbt package' or 'sbt publish', for what it matters, in a fresh Activator 'play-scala' application (or any application) will ignore the assets and the jar won't be generated. Only a play project can generate this jar typing 'dist'

The documentation talks about web-assets:package, that doesn't exist.

Regards,

Add support for Sencha ExtJS 5

Hello,

Who would have interest in a sbt-web plugin for Sencha ExtJS 5 ?
Well, I would !

Are there already any plans ?

sbt-web tester does not work

/home/antonkulaga/denigma/sbt-web/build.sbt:12: error: eof expected but ';' found.
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
``

Unable to get incremental execution to work without clean

I'm trying to use sbt-rjs in a non-play sbt project.

My plugins.sbt includes this:

addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.0-RC3")

And my build.sbt includes this:

import RjsKeys._
import WebJs._

lazy val root = (project in file(".")).enablePlugins(SbtWeb)

JsEngineKeys.engineType := JsEngineKeys.EngineType.Node

pipelineStages := Seq(rjs)

The first time I invoke sbt web-stage everything works perfectly, but on subsequent re-runs nothing happens. The only way I can get the pipeline to run again is if I remove the resulting artifacts from my target directory. So sbt ~web-stage won't work, I have to do something like ~;clean; web-stage.

Enable the asset pipeline in run mode

The asset pipeline stages are only executed when running in production or stage mode. Can we get support for using the asset pipeline while in play run mode so we can develop against it?

Or perhaps there is a way to do this now with some sbt configuring?

Building sbt-web plugins that depend on npm packages

I started working on a source task plugin for running ES6 code through the babel transpiler (https://github.com/onelson/sbt-babeljs) following @huntc's excellent sbt-stylus example, but ran into a snag... I'm not exactly sure how to get the node module into my plugin without building a webjar for it. I believe there should be a webjar for babel, but there isn't one currently and I don't yet know how best to build one without just putting in a request and waiting for it to be delivered by the webjar folks (which is a really lame way to do things - I'd rather learn how to help myself).

In the meantime, I'm looking for other ways to get the js into my plugin so that I can complete development, then later trade out for a webjar dependency once it becomes available.

According to the docs here, it looks as though I should be able to add a package.json to my project root and the packages should be available to my plugin at runtime. Unfortunately, this doesn't seem to be working for me and I fear I've missed a step somehow (scripted tests fail with Error: Cannot find module 'babel-core'). Docs suggest I also need to declare that my task depends on nodeModules in Plugin which I believe I have done (https://github.com/onelson/sbt-babeljs/blob/master/src/main/scala/com/theomn/sbt/babeljs/SbtBabelJS.scala#L56).

Anyway, I'm looking for some advice on how to proceed.

Cheers,
Owen

sbt-web workflow vs. Grunt workflow

We were trying to merge our grunt build into sbt-web. For that we were just using the sbt-coffeescript and the sbt-stylus plugin to compile our assets. This works to some extend. What happens is:

  • When a .styl file is saved, sbt does not see this as a changed file and does not start recompiling stylus (running with ~run). This only happens when we press reload in the browser.
  • The next thing is that reloading the browser also restarts the entire play app and not just compiles the assets and loads the view again. Is this the current behaviour or are we doing something wrong?

From a workflow perspective compared to Grunt this is very poor. The workflow our frontend devs are used to (and which we would like to experience with sbt-web as well so I can convince them to change ;) is:

  • Change a source file, i.e. .styl file
  • The grunt watch task sees the change, compiles the stylus file and writes it into the public folder (This does not happen with sbt-web as well as everything is in target/public which might be problematic with browsersync?)
  • http://browsersync.io/ sees the change and updates the page without refreshing it

The major issue seems to be here that changing a .styl file does not trigger the recompilation on save in sbt-web so browsersync can not see the change (I could set it up to watch target/public/css, i.e.).

Any ideas or thoughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.