Search code examples
webpackscala.jsscalajs-bundler

How do I set a javascript global variable to a module with ScalaJS Bundler


I am using Scalajs-Bundler to manage NPM dependencies for my Scala.js project. I am trying to use scalajs-react-components to provide Scala.js facades for Material-ui components, but the library requires a global variable mui defined as follows:

var mui = require("material-ui");
mui.Styles = require("material-ui/styles");
mui.SvgIcons = require('material-ui/svg-icons/index');

window.mui = mui;

I have the line webpackConfigFile := Some(baseDirectory.value/"webpack.config.js") in my build.sbt to allow me to customize scalajs-bundler's Webpack configuration. I have the following in webpack.config.js:

var webpack = require('webpack');

module.exports = require('./scalajs.webpack.config.js');

module.exports.entry.material_ui = './mui.js';
module.exports.output.filename = "[name]-bundle.js";

and in mui.js

var mui = require("material-ui");
mui.Styles = require("material-ui/styles");
mui.SvgIcons = require('material-ui/svg-icons/index');

window.mui = mui;

However, the resulting bundle does not include the definition of the mui variable. If webpack.config.js is instead

var webpack = require('webpack');

module.exports = require('./scalajs.webpack.config.js');

module.exports.entry.material_ui = './mui.js';
module.exports.output.filename = "final-bundle.js";

The definition of the mui variable is included but the actual Scala.js app is not!

I've also tried putting the definition of the mui variable directly in the webpack.config.js file as

var webpack = require('webpack');

module.exports = require('./scalajs.webpack.config.js');

var mui = require("material-ui");
mui.Styles = require("material-ui/styles");
mui.SvgIcons = require('material-ui/svg-icons/index');

window.mui = mui;

but this does not word since window is undefined in the webpack configuration script.

How do I set the mui global variable?

(full build.sbt):

import org.scalajs.sbtplugin.cross.CrossType
import sbt.Keys.{organization, scalacOptions}

version := "1.0-SNAPSHOT"

inThisBuild(Seq(
  scalaVersion := "2.12.2",
  name := """CubScout""",
  organization := "com.robocubs4205",
  version := "1.0-SNAPSHOT",
  scalacOptions += "-feature",
  resolvers += "Atlassian" at "https://maven.atlassian.com/content/repositories/atlassian-public/"
))

lazy val server = (project in file("server")).settings(
  libraryDependencies ++= Seq(
    guice,
    "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.0" % Test,
    "com.typesafe.play" %% "play-slick" % "3.0.0",
    "com.typesafe.play" %% "play-slick-evolutions" % "3.0.0",
    evolutions
  ),
  libraryDependencies += "com.h2database" % "h2" % "1.4.194",
  libraryDependencies ++= Seq(
    "com.nulab-inc" %% "scala-oauth2-core" % "1.3.0",
    "com.nulab-inc" %% "play2-oauth2-provider" % "1.3.0"
  ),
  //libraryDependencies += "com.mohiva" %% "play-silhouette" % "5.0.0",

  libraryDependencies += "com.github.t3hnar" %% "scala-bcrypt" % "3.1"


  // Adds additional packages into Twirl
  //TwirlKeys.templateImports += "com.robocubs4205.cubscout.controllers._",

  // Adds additional packages into conf/routes
  // play.sbt.routes.RoutesKeys.routesImport += "com.robocubs4205.binders._",
).dependsOn(commonJVM).enablePlugins(PlayScala)

lazy val client = (project in file("client")).settings(
  scalaJSUseMainModuleInitializer := true,
  webpackConfigFile := Some(baseDirectory.value/"webpack.config.js"),
  libraryDependencies ++= Seq(
    "org.scala-js" %%% "scalajs-dom" % "0.9.1"
  ),
  libraryDependencies += "com.github.japgolly.scalajs-react" %%% "core" % "1.1.0",
  libraryDependencies += "com.github.japgolly.scalajs-react" %%% "extra" % "1.1.0",
  libraryDependencies += "com.olvind" %%% "scalajs-react-components" % "0.7.0",
  npmDependencies in Compile ++= Seq(
    "react" -> "15.6.1",
    "react-dom" -> "15.6.1",
    "material-ui" -> "0.17.0"),
  scalaSource in Compile := baseDirectory.value / "app",
  scalaSource in Test := baseDirectory.value / "test",
  javaSource in Compile := baseDirectory.value / "app",
  javaSource in Test := baseDirectory.value / "test",
  resourceDirectory in Compile := baseDirectory.value / "resources"
).enablePlugins(ScalaJSPlugin, ScalaJSBundlerPlugin).
  dependsOn(commonJS)

lazy val commonJVM = common.jvm

lazy val commonJS = common.js

lazy val common = (crossProject.crossType(CrossType.Pure) in file("common")).settings(
  libraryDependencies += "io.lemonlabs" %% "scala-uri" % "0.4.16",
  libraryDependencies += "com.typesafe.play" %% "play" % "2.6.2",
  libraryDependencies += "commons-codec" % "commons-codec" % "1.10"
).jvmSettings(
  libraryDependencies += "org.scala-js" %% "scalajs-stubs" % scalaJSVersion % "provided"
).jsSettings(
  libraryDependencies += "org.scala-js" %%% "scalajs-java-time" % "0.2.2"
)

onLoad in Global := (Command.process("project server", _: State)) compose (onLoad in Global).value

Solution

  • I misunderstood how webpack entry points worked. a webpack.config.js that works is:

    var webpack = require('webpack');
    
    module.exports = require('./scalajs.webpack.config.js');
    
    Object.keys(module.exports.entry).forEach(function(key){
        module.exports.entry[key] = ['./mui.js'].concat(module.exports.entry[key])
    });
    

    This adds './mui.js' to the beginning of the array of files for each entry point (by default, there is only one entry point which is defined by scalajs-bundler)