Skip to content

Commit

Permalink
Webpack4 support (#223)
Browse files Browse the repository at this point in the history
  • Loading branch information
cquiroz authored and julienrf committed Mar 20, 2018
1 parent 9c3cd1b commit 4aaa49d
Show file tree
Hide file tree
Showing 36 changed files with 227 additions and 95 deletions.
1 change: 1 addition & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ environment:
- CI_SBT_VERSION: 0.13.16
- CI_SBT_VERSION: 1.0.2
install:
- ps: Install-Product node 6
- cmd: choco install sbt --version 0.13.15 -ia "INSTALLDIR=""C:\sbt"""
- cmd: SET PATH=C:\sbt\bin;%JAVA_HOME%\bin;%PATH%
- cmd: SET SBT_OPTS=-XX:MaxPermSize=2g -Xmx4g
Expand Down
6 changes: 6 additions & 0 deletions manual/src/ornate/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Version 0.12.0

> 2018 March 20
* [#223](https://github.com/scalacenter/scalajs-bundler/pull/223): Webpack4 support

## Version 0.11.0

> 2018 March 15
Expand Down
14 changes: 14 additions & 0 deletions manual/src/ornate/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,17 @@ webpackExtraArgs := Seq("--profile", "--progress", "true")

**Note** Params are passed verbatim, they are not sanitized and could produce errors when passed to webpack.
In particular, don't attempt to override the `--config` param.

## How to use webpack 4 (Experimental)

`scalajs-bundler` (version 0.12.0 onwards) supports webpack 4. To enable webpack 4, set the correct versions in `build.sbt`

-~~~ scala
version in webpack := "4.1.1"

version in startWebpackDevServer := "3.1.1"
-~~~

Additionally, you need to update any webpack plugins your config uses, to Webpack 4 compatible versions.

Webpack 4 has the potential to substantially reduce your webpack compilation times (80% reductions have been observed but your mileage may vary)
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ object PackageJson {
fullClasspath: Seq[Attributed[File]],
currentConfiguration: Configuration,
webpackVersion: String,
webpackDevServerVersion: String
webpackDevServerVersion: String,
webpackCliVersion: String
): Unit = {
val npmManifestDependencies = NpmDependencies.collectFromClasspath(fullClasspath)
val dependencies =
Expand All @@ -39,20 +40,27 @@ object PackageJson {
else npmManifestDependencies.testDependencies
)

val sourceMapLoaderVersion =
val sourceMapLoaderVersion =
NpmPackage(webpackVersion).major match {
case Some(1) | Some(2) => "0.1.5"
case Some(3) => "0.2.1"
case Some(x) => sys.error(s"Unsupported webpack major version $x")
case None => sys.error("No webpack version defined")
case Some(3) => "0.2.1"
case Some(4) => "0.2.3"
case Some(x) => sys.error(s"Unsupported webpack major version $x")
case None => sys.error("No webpack version defined")
}

val webpackPackages =
NpmPackage(webpackVersion).major match {
case Some(1) | Some(2) | Some(3) => Seq("webpack" -> webpackVersion)
case Some(4) => Seq("webpack" -> webpackVersion, "webpack-cli" -> webpackCliVersion)
case _ => Seq.empty
}

val devDependencies =
npmDevDependencies ++ (
if (currentConfiguration == Compile) npmManifestDependencies.compileDevDependencies
else npmManifestDependencies.testDevDependencies
) ++ Seq(
"webpack" -> webpackVersion,
) ++ webpackPackages ++ Seq(
"webpack-dev-server" -> webpackDevServerVersion,
"concat-with-sourcemaps" -> "1.0.4", // Used by the reload workflow
"source-map-loader" -> sourceMapLoaderVersion // Used by webpack when emitSourceMaps is enabled
Expand Down
44 changes: 43 additions & 1 deletion sbt-scalajs-bundler/src/main/scala/scalajsbundler/Webpack.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,28 @@ package scalajsbundler
import sbt._

import scalajsbundler.util.{Commands, JS}
import org.scalajs.core.tools.linker.StandardLinker.Config

object Webpack {
// Represents webpack 4 modes
sealed trait WebpackMode {
def mode: String
}
case object DevelopmentMode extends WebpackMode {
val mode = "development"
}
case object ProductionMode extends WebpackMode {
val mode = "production"
}
object WebpackMode {
def apply(sjsConfig: Config): WebpackMode = {
if (sjsConfig.semantics.productionMode) {
ProductionMode
} else {
DevelopmentMode
}
}
}

/**
* Copies the custom webpack configuration file and the webpackResources to the target dir
Expand Down Expand Up @@ -40,6 +60,7 @@ object Webpack {
entry: BundlerFile.WebpackInput,
webpackConfigFile: BundlerFile.WebpackConfig,
libraryBundleName: Option[String],
mode: WebpackMode,
log: Logger
): Unit = {
log.info("Writing scalajs.webpack.config.js")
Expand Down Expand Up @@ -109,6 +130,20 @@ object Webpack {
)
)
)
case Some(4) =>
Seq(
"mode" -> JS.str(mode.mode),
"devtool" -> JS.str("source-map"),
"module" -> JS.obj(
"rules" -> JS.arr(
JS.obj(
"test" -> JS.regex("\\.js$"),
"enforce" -> JS.str("pre"),
"use" -> JS.arr(JS.str("source-map-loader"))
)
)
)
)
case Some(x) => sys.error(s"Unsupported webpack major version $x")
case None => sys.error("No webpack version defined")
}
Expand All @@ -126,6 +161,8 @@ object Webpack {
* @param webpackResources Additional resources to be copied to the working folder
* @param entry Scala.js application to bundle
* @param targetDir Target directory (and working directory for Nodejs)
* @param extraArgs Extra arguments passed to webpack
* @param mode Mode for webpack 4
* @param log Logger
* @return The generated bundles
*/
Expand All @@ -137,9 +174,10 @@ object Webpack {
entry: BundlerFile.Application,
targetDir: File,
extraArgs: Seq[String],
mode: WebpackMode,
log: Logger
): BundlerFile.ApplicationBundle = {
writeConfigFile(emitSourceMaps, entry, generatedWebpackConfigFile, None, log)
writeConfigFile(emitSourceMaps, entry, generatedWebpackConfigFile, None, mode, log)

val configFile = customWebpackConfigFile
.map(Webpack.copyCustomWebpackConfigFiles(targetDir, webpackResources))
Expand All @@ -164,6 +202,8 @@ object Webpack {
* @param webpackResources Additional webpack resources to include in the working directory
* @param entryPointFile The entrypoint file to bundle dependencies for
* @param libraryModuleName The library module name to assign the webpack bundle to
* @param extraArgs Extra arguments passed to webpack
* @param mode Mode for webpack 4
* @param log Logger
* @return The generated bundle
*/
Expand All @@ -175,13 +215,15 @@ object Webpack {
entryPointFile: BundlerFile.EntryPoint,
libraryModuleName: String,
extraArgs: Seq[String],
mode: WebpackMode,
log: Logger
): BundlerFile.Library = {
writeConfigFile(
emitSourceMaps,
entryPointFile,
generatedWebpackConfigFile,
Some(libraryModuleName),
mode,
log
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ object LibraryTasks {
webpackResourceFiles ++ compileResources
val cacheLocation = streams.value.cacheDirectory / s"${stage.key.label}-webpack-libraries"
val extraArgs = (webpackExtraArgs in stage).value
val webpackMode = Webpack.WebpackMode((scalaJSLinkerConfig in stage).value)

val cachedActionFunction =
FileFunction.cached(
Expand All @@ -96,6 +97,7 @@ object LibraryTasks {
entryPointFile,
mode.exportedName,
extraArgs,
webpackMode,
log
)
.file)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ object PackageJsonTasks {
configuration: Configuration,
webpackVersion: String,
webpackDevServerVersion: String,
webpackCliVersion: String,
streams: Keys.TaskStreams
): BundlerFile.PackageJson = {

Expand All @@ -40,7 +41,8 @@ object PackageJsonTasks {
npmResolutions.toString,
fullClasspath.map(_.data.name).toString,
webpackVersion,
webpackDevServerVersion
webpackDevServerVersion,
webpackCliVersion
).mkString(",")

val packageJsonFile = targetDir / "package.json"
Expand All @@ -60,7 +62,8 @@ object PackageJsonTasks {
fullClasspath,
configuration,
webpackVersion,
webpackDevServerVersion
webpackDevServerVersion,
webpackCliVersion
)
()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,14 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
"Custom arguments to webpack-dev-server"
)

/**
* Version of webpack-cli
*
* @group settings
*/
val webpackCliVersion: SettingKey[String] =
settingKey[String]("Version of webpack-cli to use")

/**
* Start background webpack-dev-server process.
*
Expand Down Expand Up @@ -454,6 +462,8 @@ object ScalaJSBundlerPlugin extends AutoPlugin {

version in webpack := "3.5.5",

webpackCliVersion := "2.0.11",

version in startWebpackDevServer := "2.11.1",

version in installJsdom := "9.9.0",
Expand Down Expand Up @@ -543,6 +553,7 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
configuration.value,
(version in webpack).value,
(version in startWebpackDevServer).value,
webpackCliVersion.value,
streams.value
),

Expand Down Expand Up @@ -610,6 +621,7 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
val targetDir = npmUpdate.value
val sjsOutputName = sjsOutput.name.stripSuffix(".js")
val bundle = targetDir / s"$sjsOutputName-bundle.js"
val webpackVersion = (version in webpack).value

val customWebpackConfigFile = (webpackConfigFile in Test).value

Expand All @@ -625,9 +637,21 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
customWebpackConfigFile match {
case Some(configFile) =>
val customConfigFileCopy = Webpack.copyCustomWebpackConfigFiles(targetDir, webpackResources.value.get)(configFile)
Webpack.run("--config", customConfigFileCopy.getAbsolutePath, loader.absolutePath, bundle.absolutePath)(targetDir, logger)
NpmPackage(webpackVersion).major match {
case Some(4) =>
// TODO: It assumes tests are run on development mode. It should instead use build settings
Webpack.run("--mode", "development", "--config", customConfigFileCopy.getAbsolutePath, loader.absolutePath, "--output", bundle.absolutePath)(targetDir, logger)
case _ =>
Webpack.run("--config", customConfigFileCopy.getAbsolutePath, loader.absolutePath, bundle.absolutePath)(targetDir, logger)
}
case None =>
Webpack.run(loader.absolutePath, bundle.absolutePath)(targetDir, logger)
NpmPackage(webpackVersion).major match {
case Some(4) =>
// TODO: It assumes tests are run on development mode. It should instead use build settings
Webpack.run("--mode", "development", loader.absolutePath, "--output", bundle.absolutePath)(targetDir, logger)
case _ =>
Webpack.run(loader.absolutePath, bundle.absolutePath)(targetDir, logger)
}
}

Set.empty
Expand Down Expand Up @@ -780,4 +804,3 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package scalajsbundler.sbtplugin
import sbt.Keys._
import sbt.{Def, _}

import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport.scalaJSLinkerConfig
import scalajsbundler.sbtplugin.ScalaJSBundlerPlugin._
import scalajsbundler.sbtplugin.ScalaJSBundlerPlugin.autoImport._
import scalajsbundler.Webpack
Expand Down Expand Up @@ -29,6 +30,7 @@ object WebpackTasks {
val log = streams.value.log
val monitoredFiles = (webpackMonitoredFiles in stage).value
val extraArgs = (webpackExtraArgs in stage).value
val webpackMode = Webpack.WebpackMode((scalaJSLinkerConfig in stage).value)

val cachedActionFunction =
FileFunction.cached(
Expand All @@ -44,6 +46,7 @@ object WebpackTasks {
entriesList,
targetDir,
extraArgs,
webpackMode,
log
).file)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.19")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.22")

addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % sys.props.getOrElse("plugin.version", sys.error("'plugin.version' environment variable is not set")))
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.19")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.22")

addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % sys.props.getOrElse("plugin.version", sys.error("'plugin.version' environment variable is not set")))
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.19")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.22")

addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % sys.props.getOrElse("plugin.version", sys.error("'plugin.version' environment variable is not set")))
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,3 @@ lazy val facade =
lazy val commonSettings = Seq(
scalaVersion := "2.11.8"
)

Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ npmDependencies in Compile ++= Seq(
)

npmDevDependencies in Compile ++= Seq(
"webpack-merge" -> "4.1.0",
"imports-loader" -> "0.7.0",
"expose-loader" -> "0.7.1"
"webpack-merge" -> "4.1.2",
"imports-loader" -> "0.8.0",
"expose-loader" -> "0.7.5"
)

webpackConfigFile in fastOptJS := Some(baseDirectory.value / "dev.webpack.config.js")
Expand Down
Loading

0 comments on commit 4aaa49d

Please sign in to comment.