GithubHelp home page GithubHelp logo

workbench's Introduction

Workbench

Example

A SBT plugin for scala-js projects to make development in the browser more pleasant.

  • Spins up a local web server on (by default) localhost:12345, whenever you're in the SBT console. Navigate to localhost:12345 in the browser and it'll show a simple page tell you it's alive. You can access any file within your project directory by going to localhost:12345/path/to/file in a browser.
  • Forwards all SBT logging from your SBT console to the browser console, so you can see what's going on (e.g. when the project is recompiling) without having to flip back and forth between browser and terminal.
  • Sends commands to tell the connected browsers to refresh/update every time your Scala.Js project completes a fastOptJS.

Check out the example app for a plug-and-play example of workbench in action.

Installation

  • Add to your project/plugins.sbt
// for sbt 1.0+
addSbtPlugin("com.lihaoyi" % "workbench" % "0.4.1")
// for sbt 0.13.x
addSbtPlugin("com.lihaoyi" % "workbench" % "0.3.1")
  • Add to your build.sbt
enablePlugins(WorkbenchPlugin)
  • For all web pages you would like to integrate with workbench, add
<script type="text/javascript" src="/workbench.js"></script>

Usage

Once the above installation steps are completed, simply open your desired HTML file via http://localhost:12345 with the URL path being any file part relative to your project root. e.g. localhost:12345/target/scala-2.12/classes/index.html. This should serve up the HTML file and connect it to workbench.

If you want to serve a defaultRootObject on http://localhost:12345 and serve only files from a root directory you can set this via:

workbenchDefaultRootObject := Some(("build/index-dev.html", "build/"))  // (defaultRootObject, rootDirectory) 

If you're accessing Workbench remotely over a slow network, you can enable compression of the transferred data with:

workbenchCompression := true

Compression is only supported on sbt 1.0+

Server Starting Behaviour

By default, the server starts up when sbt loads. Ie, starting the sbt terminal via sbt will start the server as well. This behaviour can be changed by adding on of the following settings to your build.sbt:

  • start the server on compilation (eg when running sbt "~fastOptJS")
workbenchStartMode := WorkbenchStartModes.OnCompile
  • start the server manually using the startWorkbenchServer task
workbenchStartMode := WorkbenchStartModes.Manual

Live Reloading

You have a choice of what you want to do when the code compiles.

Refresh page

This will to make any client browsers refresh every time fastOptJS completes, saving you flipping back and forth between SBT and the browser to refresh the page after compilation is finished. This is the default behavior.

Splice changes

// WorkbenchPlugin must NOT be enabled at the same time
enablePlugins(WorkbenchSplicePlugin)

This is an experimental feature that aims to perform an update to the code running in the browser without losing the state of the running code! Thus you can make changes to the code and have them immediately appear in the program, without having to restart and lose the current state of the application. See this video for a demo of it in action.

This live splicing is not doable in the general case, but only for some subset of changes:

  • Changes inside method bodies
  • Adding new defs and lazy vals to classes/objects
  • Creating entirely new classes/objects

This means that there are many changes that spliceBrowsers does not support, such as.

  • Adding new vals and vars to classes/objects
  • Modifying inheritance hierarchies
  • Changing the type of an existing val/var/lazy val
  • Renaming classes

And many more. If the change is something that Workbench does not support, you'll see errors in the browser console:

Example

And you'll need to refresh the page.

Note that you have to turn off the Scala.js inliner (as shown in the above SBT snippet) in order to have this work. The inliner performs inlinings across class and method boundaries that makes it hard to predict whether or not the live-splicer will work.

Lastly, note that spliceBrowsers does not retroactively modify the state of the application as if the changes in the code had always been present. For example, values set by the constructor in instances of a class will remain as-is even if you modify the class constructor; only new instances will be affected by the modified constructor.

In general, it is entirely possible to get into weird/invalid states due to this live-splicing, and the general solution is simply to refresh the page.


With this done, you should be receiving the SBT logspam (compilation, warnings, errors) in your browse console, and the page should be automatically refreshing/updating when the application gets recompiled. If you have problems setting this up, try starting from the example app and working from there.

Development

To develop, go into example/ and run sbt ~fastOptJS. Then you can go to

http://localhost:12345/target/scala-2.12/classes/index-dev.html

and see a small sierpinski-triangle application. Editing the code within example/ should cause the SBT log-spam to appear in the browser console, and changes (e.g. changing the color of the background fill) should cause a recompile and updating of the browser animation.

To make changes to workbench, modify the workbench source code and stop/re-run sbt ~fastOptJS. When workbench finishes re-compiling, SBT re-starts and the page becomes accessible, your changes to workbench will take effect.

Pull requests welcome!

Change Log

0.4.1

  • Allow host/port configuration

0.4.0 (sbt 1.0+ only)

  • Support sbt 1.0+

0.3.1 (sbt 0.13.x only)

  • Support for custom defaultRootObject and rootDirectory (by @torstenrudolf)
  • Custom Server starting behaviour (by @torstenrudolf)
  • Support multiple concurrent clients (by @torstenrudolf)

0.3.0

  • Migration to AutoPlugins
  • Removal of updateBrowsers feature, made obsolete by increased speed of fastOptJS
  • General upgrade of dependencies

0.2.3

  • Upgraded uPickle, removed need for special resolver

0.2.2

  • First implementation of spliceBrowsers

0.2.1

  • Added missing resolver http://dl.bintray.com/non/maven

0.2.0

  • First implementation of workbench client in Scala.js

0.1.5

  • Properly kill the spray server on plugin unload, sbt reload now works
  • Swap out play-json with upickle
  • (Internally) separate Spray server code with SBT madness

License

The MIT License (MIT)

Copyright (c) 2013 Li Haoyi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

workbench's People

Contributors

hadesgames avatar hung-phan avatar japgolly avatar jodersky avatar lihaoyi avatar matthughes avatar nightscape avatar ochrons avatar oyvindberg avatar peluko avatar shaagerup 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  avatar  avatar  avatar

workbench's Issues

Workbench incompatible with Play 2.7.0

I've just upgraded from Play 2.6.20 to Play 2.7.0 and have noticed an incompatible version of Akka when running startWorkbenchServer.

sbt:admin> startWorkbenchServer
Detected java.lang.NoSuchMethodError error, which MAY be caused by incompatible Akka versions on the classpath. Please note that a given Akka version MUST be the same across all modules of Akka that you are using, e.g. if you use akka-actor [2.5.18 (resolved from current classpath)] all other core Akka modules MUST be of the same version. External projects like Alpakka, Persistence plugins or Akka HTTP etc. have their own version numbers - please make sure you're using a compatible set of libraries.                 

As a test I cloned PR #49 that updated Akka and other libraries and ran publishLocal. I'm pleased to announce that this pull request fixed the issue for me.

Could we please get his merged so others can update to Play 2.7.0?

Readme not making sense...

/quote You can replace fullOptJs in the built.sbt file with fastOptJS, and swapping the reference to client-opt.js to client-fastopt.js, if you want to speed up the development cycle.

Im not sure where one would change the 'reference', and as far as I can tell it is hard coded in the plugin here:

getClass.getClassLoader.getResourceAsStream("client-opt.js")

Is there any other way, or do we just have to use the client-opt.js ?

Add support for Play server

This currently does not work with Play, as the play server serves the files dynamically, while workbench tries to access them directly from filesystem.

Either there could be Play integration, or maybe it could fetch the server files from the server instead of from filesystem?

Unable to open any project with workbench in Intellij idea

I can't open any project of yours that uses workbench due to (now trying roll) :

[info] Loading project definition from ~/src/scalajs/roll/project/project
[info] Loading project definition from ~/src/scalajs/roll/project
[info] Set current project to games (in build file:~/src/scalajs/roll/)
[info] Defining *:artifactPath
[info] The new value will be used by no settings or tasks.
[info] Reapplying settings...
[error] akka.actor.InvalidActorNameException: actor name [simple-service-actor] is not unique!

I quadruple checked there is no other java process, it's really

  1. no java process
  2. open idea
  3. open any workbench project of yours

I was trying to figure that out 2-3 weeks back, but I couldn't ... Idea just triggers it twice or something. Due to this error one can open a project with workbench only if workbench is disabled prior to opening in idea.

Add a gitter channel

I would like to ask some questions about this project which do not belong in an issue.
Would it be possible to have a gitter channel for this project for general inquiries?

Allow client to specify custom url -> file mapping

I'd like to keep production and development URLs the same, and thus to avoid using urls to target directory. It would be good to allow client to provide mapping between the URLs and files.

I made a prototype in 76a1017.

What do you think? I'm happy to make a pull request if the commit is ok.

Workbench causes cyclic dependency issue with sbt-heroku plugin

I'm not familiar enough with SBT to understand the cause, but there appears to be a negative interaction between workbench and sbt-heroku (heroku/heroku-sbt-plugin#30) leading to SBT failing entirely due to a cyclic dependency.

[info] Loading project definition from /Users/tel/Dropbox/proj/qubit/project
Cyclic reference involving
   {file:/Users/tel/Dropbox/proj/qubit/}ui/*:extraLoggers
   {file:/Users/tel/Dropbox/proj/qubit/}/*:extraLoggers
    at sbt.Dag$Cyclic.$colon$colon(Dag.scala:67)
    at sbt.Dag$.sbt$Dag$$visit$1(Dag.scala:27)
    at sbt.Dag$$anonfun$visitAll$1$1.apply(Dag.scala:23)
    at sbt.Dag$$anonfun$visitAll$1$1.apply(Dag.scala:23)
    at scala.collection.Iterator$class.foreach(Iterator.scala:727)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1157)
    at scala.collection.MapLike$DefaultValuesIterable.foreach(MapLike.scala:206)
    at sbt.Dag$.visitAll$1(Dag.scala:23)
    at sbt.Dag$.topologicalSort(Dag.scala:33)
    at sbt.Init$class.sort(Settings.scala:152)
    at sbt.Def$.sort(Def.scala:10)
    at sbt.Init$class.make(Settings.scala:146)
    at sbt.Def$.make(Def.scala:10)
    at sbt.Load$.apply(Load.scala:145)
    at sbt.Load$.defaultLoad(Load.scala:36)
    at sbt.BuiltinCommands$.liftedTree1$1(Main.scala:492)
    at sbt.BuiltinCommands$.doLoadProject(Main.scala:492)
    at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:484)
    at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:484)
    at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:59)
    at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:59)
    at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:61)
    at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:61)
    at sbt.Command$.process(Command.scala:93)
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:96)
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:96)
    at sbt.State$$anon$1.process(State.scala:184)
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:96)
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:96)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
    at sbt.MainLoop$.next(MainLoop.scala:96)
    at sbt.MainLoop$.run(MainLoop.scala:89)
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:68)
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:63)
    at sbt.Using.apply(Using.scala:24)
    at sbt.MainLoop$.runWithNewLog(MainLoop.scala:63)
    at sbt.MainLoop$.runAndClearLast(MainLoop.scala:46)
    at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:30)
    at sbt.MainLoop$.runLogged(MainLoop.scala:22)
    at sbt.StandardMain$.runManaged(Main.scala:54)
    at sbt.xMain.run(Main.scala:29)
    at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:109)
    at xsbt.boot.Launch$.withContextLoader(Launch.scala:128)
    at xsbt.boot.Launch$.run(Launch.scala:109)
    at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35)
    at xsbt.boot.Launch$.launch(Launch.scala:117)
    at xsbt.boot.Launch$.apply(Launch.scala:18)
    at xsbt.boot.Boot$.runImpl(Boot.scala:41)
    at xsbt.boot.Boot$.main(Boot.scala:17)
    at xsbt.boot.Boot.main(Boot.scala)
[error] Cyclic reference involving
[error]    {file:/Users/tel/Dropbox/proj/qubit/}ui/*:extraLoggers
[error]    {file:/Users/tel/Dropbox/proj/qubit/}/*:extraLoggers
[error] Use 'last' for the full log.

My build.sbt looks like

lazy val commonSettings = Seq(
  organization := "jspha",
  scalaVersion := "2.11.8",
  version := "1.0-SNAPSHOT",
  resolvers += Resolver.sonatypeRepo("snapshots")
)

lazy val http4sVersion = "0.14.0-SNAPSHOT"
lazy val doobieVersion = "0.2.3"

lazy val server = project.in(file("server"))
  .settings(commonSettings: _*)
  .dependsOn(sharedJvm)
  .settings(
    libraryDependencies ++= Seq(
      "org.http4s" %% "http4s-dsl" % http4sVersion,
      "org.http4s" %% "http4s-blaze-server" % http4sVersion,

      "org.tpolecat" %% "doobie-core" % doobieVersion,
      "org.tpolecat" %% "doobie-contrib-postgresql" % doobieVersion,
      "org.tpolecat" %% "doobie-contrib-specs2" % doobieVersion,

      "org.slf4j" % "slf4j-simple" % "1.6.4"
    )
  )
  .settings(
    (resources in Compile) <+= Def.task {
      (artifactPath in (ui, Compile, fullOptJS)).value
    } dependsOn (fullOptJS in (ui, Compile))
  )
  .enablePlugins(JavaServerAppPackaging)

lazy val shared = crossProject.crossType(CrossType.Pure).in(file("shared"))
  .settings(commonSettings: _*)

lazy val sharedJvm = shared.jvm.settings(name := "sharedJvm")
lazy val sharedJs = shared.js.settings(name := "sharedJs")

lazy val ui = project.in(file("ui"))
  .settings(commonSettings: _*)
  .dependsOn(sharedJs)
  .enablePlugins(ScalaJSPlugin)
  .settings(workbenchSettings)
  .settings(
    bootSnippet := "jspha.qubit.ui.Runtime().main();",
    refreshBrowsers <<= refreshBrowsers.triggeredBy(fastOptJS in Compile)
  )

Allow proxying sub-paths to other server implementation for better development cycle

When developing react apps, I've been using webpack proxy to forward /api/* to e.g. localhost:9000/api/* for speedy development of single page web apps.
Correct me if I'm wrong, but I don't see any way to proxy servers with workbench.

Effectively, this gives my web-app the illusion that it is being hosted on the actual server allowing me to keep relative paths everywhere. (autowire is not an option for me currently).

Would it be much work to add a configuration to forward some sub-path to a user chosen URL?

Use workbench with another server

I use a Spray server to serve the HTML and static files but I would like to use the workbench plugin (refresh on packageJS & console forwarding) in the same way I use LiveReload for CSS changes.

I tried to include <script type="text/javascript" src="http://localhost:12345/workbench.js"></script> in the HTML, but it doesn't work well in Chrome and not at all in Safari. The Access-Control-Allow-Origin header seems to cause troubles.

Is that a supported use case? How should I do it?

js error: Cannot read property 'cloneNode' of null

I see this in my Chrome console after upgrading workbench to 0.2.0. (ScalaJS is 0.5.4)

Uncaught TypeError: Cannot read property 'cloneNode' of null workbench.js:60
Ng.c workbench.js:60
Eg workbench.js:65
(anonymous function) workbench.js:520
(anonymous function) workbench.js:521

Intellij 13.1 integration

Intellij's new SBT project importer added in 13.1 really doesn't like workbench enabled projects. I have some mixed luck disabling workbench, importing and then re-enabling workbench, but that appears to break every time I restart intellij.

Body not resetting to initial state when using updateBrowsers

Hi, I'm new to scala.js and workbench so I might just have made a newbie mistake.

The workbench docs states this about updateBrowsers:
"Returning the state of document.body to the initial state before any javascript was run"
which I have been having troubles getting to work.

I have modified the master branch of workbench-example-app to replicate my issue and made a gif to show what is happening.

https://github.com/Kemichal/workbench-example-app

workbench-issue

In short, when I change ScalaJSExample.scala workbench triggers and adds a child to body, but it does not return the state of body before doing so.

Fix missing client-opt.js.map

Project that uses workbench.js gets an annoying 404 on client-opt.js.map in javascript console.

A quick fix would be to publish a new workbench version with emitSourceMaps := false

A proper fix would be to include client-opt.js.map (pointing to tagged github source) with the jar and have the Server serving it.

WorkbenchSplicePlugin causes refreshes

The line override def requires = WorkbenchPlugin causes the 'refresh' plugin to load. It should be override def requires = WorkbenchBasePlugin.

scalaVersion in ThisBuild := "2.12.4"

val client = project.in(file("client"))
  .settings(
    name := "test-client"
  )
  .enablePlugins(ScalaJSPlugin, WorkbenchSplicePlugin)
workbench.js:121:160
Workbench connected
workbench.js:438:172
workbench: Splicing http://localhost:12345\client\target\scala-2.12\test-client-fastopt.js
workbench.js:124:117
workbench: Checking test-client-jsdeps.js.js
workbench.js:124:117
workbench: Checking test-client-jsdeps.js
workbench.js:124:117
workbench: Checking test-client-fastopt.js.js
workbench.js:124:117
workbench: Checking test-client-fastopt.js
workbench.js:124:117
workbench: Reloading Pages...

If I override that, it does load modified files without refreshing, but none of the 'modify methods while preserving state' behaviour works - I don't think any of the munge regexes work on the current fastOptJS.

feature: allow embedded server to define "get" directories to create virtual filesystem

I'll try to create a pull request but I wanted to document this feature here.

This would work in the same spirit as sprockets. It looks like the spray server is being used so getting access to the server should allow you to add your own "get"s.

Motivation:
When developing web apps, you may have many assets strewn about your filesystem or directory structure. You want to use the final path structure in your files (links and scripts). A virtual filesystem creating by mapping "gets" should allow you to do this for development purposes. This would would work regardless of the IDE you are using and whatever resource management it performs.

Question regarding to host/port for client notification

Hi there,

I have some questions regarding to setting up workbench with other servers. Previously, workbench can make request /notifications to localhost:12345 by default. However, for now if I server my webpage under any server like play framework it will make request to localhost:9000 which is unexpected. Is there any way, I can make workbench client request localhost:12345 instead.

screen shot 2017-12-20 at 8 33 46 am

Absolute paths in the imported plugin library

The library is trying to access absolute paths that are not present in my computer.

This is the console output right after I've loaded the page I'm developing:

Resource interpreted as Script but transferred with MIME type text/plain: "http://localhost:12345/workbench.js". index.html:15
Resource interpreted as Script but transferred with MIME type text/plain: "http://localhost:12345/workbench.js". index.html:15
Loading Workbench workbench.js:61
Workbench connected workbench.js:374
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/package.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/core/Core.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/core/Dynamic.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/core/Flow.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/core/SpinSet.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/core/Propagator.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/ops/package.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map
Failed to locate workspace file mapped to URL file:///Users/haoyi/Dropbox%20(Personal)/Workspace/scala.rx/js/../shared/main/scala/rx/ops/Reactives.scala from source map http://localhost:12345/scalajs/target/scala-2.11/mfl-fastopt.js.map

This is how I'm loading the plugin:

project/plugins.sbt

resolvers += "spray repo" at "http://repo.spray.io"                                                                                         

resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"                                                         

addSbtPlugin("com.lihaoyi" % "workbench" % "0.2.2") 

build.sbt

workbenchSettings                                                                                                                           

bootSnippet := "com.gabrielbezerra.mfl.Main().main();"                                                                     

updateBrowsers <<= updateBrowsers.triggeredBy(ScalaJSKeys.fastOptJS in Compile)  

500 errors from /notifications with >1 client

When more than one client connects to workbench, the js console spouts a 500 error every 40 seconds or so, and fails to refresh on rebuild. This was super confusing and hard to debug. It'd be awesome to support more than one client pointing at the server, but failing that it'd be nice to have a friendlier error message :)

SBT missing resolvers

I had to add the following to get it to work.

resolvers += "spray repo" at "http://repo.spray.io"

resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"

If SBT allows it, it would be good to add this to the plugin. If not, we should add it to the readme.

Changing port number ?

Maybe I'm totally dumb, but I didn't found the way to change the '12345' port.
Either provide a simple way to change it, or please document this for n00b like me. ;)

Workbench incompatible with Scala.js 1.0.0

Hello,

it looks that the current build of Workbench is incompatible with Scala.js 1.0.0, do you have any plans to add support for this upcoming major version?

[error] java.lang.NoClassDefFoundError: org/scalajs/sbtplugin/ScalaJSPlugin$AutoImport$
[error] 	at com.lihaoyi.workbench.WorkbenchPlugin$.<init>(WorkbenchPlugin.scala:26)
[error] 	at com.lihaoyi.workbench.WorkbenchPlugin$.<clinit>(WorkbenchPlugin.scala)
[error] 	at java.lang.Class.forName0(Native Method)
[error] 	at java.lang.Class.forName(Class.java:348)
[error] 	at sbt.internal.inc.ModuleUtilities$.getObject(ModuleUtilities.scala:20)
[error] 	at sbt.internal.inc.ModuleUtilities$.getCheckedObject(ModuleUtilities.scala:27)
[error] 	at sbt.internal.inc.ModuleUtilities$.$anonfun$getCheckedObjects$1(ModuleUtilities.scala:31)
[error] 	at scala.collection.immutable.Stream.$anonfun$map$1(Stream.scala:415)
[error] 	at scala.collection.immutable.Stream$Cons.tail(Stream.scala:1169)
[error] 	at scala.collection.immutable.Stream$Cons.tail(Stream.scala:1159)
[error] 	at scala.collection.generic.Growable.loop$1(Growable.scala:54)
[error] 	at scala.collection.generic.Growable.$plus$plus$eq(Growable.scala:58)
[error] 	at scala.collection.generic.Growable.$plus$plus$eq$(Growable.scala:50)
[error] 	at scala.collection.mutable.ListBuffer.$plus$plus$eq(ListBuffer.scala:186)
[error] 	at scala.collection.mutable.ListBuffer.$plus$plus$eq(ListBuffer.scala:44)
[error] 	at scala.collection.TraversableLike.$plus$plus(TraversableLike.scala:147)
[error] 	at scala.collection.TraversableLike.$plus$plus$(TraversableLike.scala:143)
[error] 	at scala.collection.immutable.List.$plus$plus(List.scala:207)
[error] 	at sbt.internal.PluginDiscovery$.discoverAll(PluginDiscovery.scala:54)
[error] 	at sbt.internal.Load$.loadPlugins(Load.scala:1267)
[error] 	at sbt.internal.Load$.loadPluginDefinition(Load.scala:1212)
[error] 	at sbt.internal.Load$.buildPlugins(Load.scala:1191)
[error] 	at sbt.internal.Load$.plugins(Load.scala:1174)
[error] 	at sbt.internal.Load$.$anonfun$loadUnit$2(Load.scala:683)
[error] 	at sbt.internal.Load$.timed(Load.scala:1343)
[error] 	at sbt.internal.Load$.$anonfun$loadUnit$1(Load.scala:683)
[error] 	at sbt.internal.Load$.timed(Load.scala:1343)
[error] 	at sbt.internal.Load$.loadUnit(Load.scala:677)
[error] 	at sbt.internal.Load$.$anonfun$builtinLoader$4(Load.scala:477)
[error] 	at sbt.internal.BuildLoader$.$anonfun$componentLoader$5(BuildLoader.scala:158)
[error] 	at sbt.internal.BuildLoader.apply(BuildLoader.scala:223)
[error] 	at sbt.internal.Load$.loadURI$1(Load.scala:539)
[error] 	at sbt.internal.Load$.loadAll(Load.scala:555)
[error] 	at sbt.internal.Load$.loadURI(Load.scala:485)
[error] 	at sbt.internal.Load$.load(Load.scala:464)
[error] 	at sbt.internal.Load$.$anonfun$apply$1(Load.scala:253)
[error] 	at sbt.internal.Load$.timed(Load.scala:1343)
[error] 	at sbt.internal.Load$.apply(Load.scala:253)
[error] 	at sbt.internal.Load$.defaultLoad(Load.scala:69)
[error] 	at sbt.BuiltinCommands$.liftedTree1$1(Main.scala:707)
[error] 	at sbt.BuiltinCommands$.doLoadProject(Main.scala:707)
[error] 	at sbt.BuiltinCommands$.$anonfun$loadProjectImpl$2(Main.scala:680)
[error] 	at sbt.Command$.$anonfun$applyEffect$4(Command.scala:134)
[error] 	at sbt.Command$.$anonfun$applyEffect$2(Command.scala:130)
[error] 	at sbt.MainLoop$.processCommand(MainLoop.scala:154)
[error] 	at sbt.MainLoop$.$anonfun$next$2(MainLoop.scala:137)
[error] 	at sbt.State$$anon$1.runCmd$1(State.scala:242)
[error] 	at sbt.State$$anon$1.process(State.scala:248)
[error] 	at sbt.MainLoop$.$anonfun$next$1(MainLoop.scala:137)
[error] 	at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error] 	at sbt.MainLoop$.next(MainLoop.scala:137)
[error] 	at sbt.MainLoop$.run(MainLoop.scala:130)
[error] 	at sbt.MainLoop$.$anonfun$runWithNewLog$1(MainLoop.scala:108)
[error] 	at sbt.io.Using.apply(Using.scala:22)
[error] 	at sbt.MainLoop$.runWithNewLog(MainLoop.scala:102)
[error] 	at sbt.MainLoop$.runAndClearLast(MainLoop.scala:58)
[error] 	at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:43)
[error] 	at sbt.MainLoop$.runLogged(MainLoop.scala:35)
[error] 	at sbt.StandardMain$.runManaged(Main.scala:113)
[error] 	at sbt.xMain.run(Main.scala:76)
[error] 	at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:109)
[error] 	at xsbt.boot.Launch$.withContextLoader(Launch.scala:128)
[error] 	at xsbt.boot.Launch$.run(Launch.scala:109)
[error] 	at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35)
[error] 	at xsbt.boot.Launch$.launch(Launch.scala:117)
[error] 	at xsbt.boot.Launch$.apply(Launch.scala:18)
[error] 	at xsbt.boot.Boot$.runImpl(Boot.scala:56)
[error] 	at xsbt.boot.Boot$.main(Boot.scala:18)
[error] 	at xsbt.boot.Boot.main(Boot.scala)

Custom "updateBrowsers" JS code / callback

It might be useful to be able to specify further steps to be done when trying to "update".

In the documentation you mention some things that are done/attempted. Some apps might require more specific steps to be performed (some DOM elements deleted, reloaded, etc.).

With such an option you'd give the user (developer) the power to adjust the JS reloading procedure to their needs.

(Disclaimer: I have not tried this project yet, just read the front-page documentation)

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.