Cookbook
- Cookbook
- How to use a custom webpack configuration file?
- Sharing webpack configuration among configuration files
- How to use npm modules from Scala code?
- How to publish a facade for an npm module?
- How to use an existing facade assuming the JS library to be exposed to the global namespace?
- How to bundle an application having several entry points as exports?
- How to improve the performance of the bundling process?
- How to select specific files from the BundlingMode.Library output
- How to rebuild and reload your page on code changes?
- How to pass extra parameters to webpack
- How to use webpack 4
- How to get and use a list of assets
How to use a custom webpack configuration file?
First, configure the webpackConfigFile
setting to refer to your configuration file:
Or, if you want to use the same configuration file for both fastOptJS
and fullOptJS
:
Then, you can write your configuration in file my.custom.webpack.config.js
.
We recommend that you reuse the configuration file generated by scalajs-bundler
and extend it, rather than writing a configuration file from scratch.
You can do so as follows (in file `my.custom.webpack.config.js``):
The key part is the require('./scalajs.webpack.config')
. It loads the configuration
file generated by scalajs-bundler so that you can tweak it. It works because your configuration
file will be copied into the internal target directory, where the scalajs-bundler generates
its configuration file, and where all the npm dependencies have been downloaded (so you can
also require
these dependencies).
By default webpack
task only actually launches webpack if it detects changes in
settings or in the custom webpack config file. Depending on your usage scenario, you might
want to monitor some other files as well (for example, if your webpack config references
some additional resources). This can be achieved by using webpackMonitoredDirectories
setting:
More fine-grained control over the list of monitored files is possible by overriding the
webpackMonitoredFiles
task.
You can find a working example of custom configuration file here.
It is also possible to configure a webpack config file to be used in reload workflow and when running the tests.
This configuration may not contain entry
and output
configuration but can be used to configure loaders etc.
These configuration files are configured using webpackConfigFile in reloadTask
or webpackConfigFile in Test
.
For example:
Sharing webpack configuration among configuration files
In addition to the configured webpack config file, all .js files in the project base directory
(as configured using the webpackResources
setting) are copied to the target directory so they can be imported
from the various configuration files.
Here are the steps to share the loader configuration among your prod and dev config files. This uses webpack-merge for convenience. The same result could be accomplished using plain js only.
- Put configuration in a common.webpack.config.js file:
- Add webpack-merge to your
npmDevDependencies
:
- Merge in the common configuration in your dev.webpack.js file:
You can find a working example of a project using a shared configuration file here.
How to use npm modules from Scala code?
Once you have added npm dependencies to the packages you are interested in, you have to import them from your code to effectively use them.
The recommended way to do that is to:
Let’s illustrate this with an example. Say that you want to write a facade for the following npm module:
The corresponding Scala.js facade looks like the following:
There are several points worth highlighting:
- The first parameter of the
@JSImport
annotation is the npm module path. This is the value you would pass to the Nodejsrequire
function ; - The second parameter of
@JSImport
is the name of the imported member, or like in our case,JSImport.Namespace
, to import the whole module instead of just one particular member ; - The facade is concrete. It can either be a Scala
object
or aclass
; - The facade has a “JS native” type.
Other styles of facades (importing a member in particular, importing functions and classes, importing local JavaScript files, etc.) can be found in these tests.
Finally, in your Scala code, just refer to the foo
object:
How to publish a facade for an npm module?
Create a project for the facade and enable the ScalaJSBundlerPlugin
as described
here.
Implement the facade as explained in the above section.
Publish the Scala.js project as usual.
Finally, to use the facade from another Scala.js project, this one needs both to add a
dependency on the facade and to enable the ScalaJSBundlerPlugin
plugin.
Projects that use the facade also have to enable the
ScalaJSBundlerPlugin
plugin, otherwise the dependencies of the facade will not be resolved.
How to use an existing facade assuming the JS library to be exposed to the global namespace?
Webpack is able to require external modules by using imports-loader and expose them to the global namespace by using expose-loader. Thus, you can write a custom webpack configuration file that uses this loaders to expose the required modules to the global namespace. Typically, this file will look like this:
Also, tweak your build.sbt
to add the corresponding NPM dependencies and to use the
custom webpack configuration file:
You can find a fully working example here.
How to bundle an application having several entry points as exports?
By default, ScalaJSBundlerPlugin
assumes that your application only has a main class, activated through
scalaJSUseMainModuleInitializer := true
, and disregards top-level exports. If you have exports that
need to be exposed as several entry points, this will not work.
In such a case, you can use BundlingMode.LibraryAndApplication()
.
build.sbt
:
Then, assuming that you defined the following library:
You can call its methods as follows from your JavaScript code:
How to improve the performance of the bundling process?
You can enable the library-only bundling mode and disable source maps:
How to select specific files from the BundlingMode.Library
output
In library-only bundling mode and
library with application bundling mode, the webpack
task
produces multiple files. In order to determine which of these files is, for instance, the
BundlerFileType.Application, you
can use the _.metadata
property of the files, like this:
How to rebuild and reload your page on code changes?
scalajs-bundler
includes a simple wrapper over webpack-dev-server to simplify your
workflow. It is exposed as two stage-level tasks (startWebpackDevServer
and
stopWebpackDevServer
).
The standard work session looks like this:
- Spawn background server process:
By default the server is started on port
8080
. UsewebpackDevServerPort
setting to change this. - Instruct SBT to rebuild on source changes:
- Now each time you change a source file, Scala.js recompiles it, and webpack-dev-server switches to the updated version.
- Shut down the background process:
Additional arguments can be passed to webpack-dev-server via webpackDevServerExtraArgs
setting. For example, you can add the following to your build.sbt
to make your page
reload on every change:
How to pass extra parameters to webpack
scalajs-bundler
invokes webpack
with a configuration generated either automatically from the build or set with webpackConfigFile
.
webpack
is then called with the following arguments:
You can add extra params to the webpack
call, for example, to increase debugging
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
scalajs-bundler
(version 0.12.0 onwards) supports webpack 4. To enable webpack 4, set the correct versions in build.sbt
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)
How to get and use a list of assets
scalajs-bundler
(version 0.13.0 onwards) will export a list of all assets produced by webpack. You can read that list on sbt
You can this list e.g. with sbt-native-packager` to add mappings as:
This will add all artifacts produced by the fully optimized Scala.JS run to the 'assets' directory of the target archive.
If you need to package additional libraries that have been downloaded by scalajs-bundler
, you can do something like:
Also, any static resources that you would like to have in the resulting archive (i.e. index.html
), should live inside the src/universal
directory of your project.