Skip to content

Commit

Permalink
Merge pull request #112 from ScalablyTyped/generate-artifacts-in-plugin
Browse files Browse the repository at this point in the history
Generate artifacts in sbt plugin
  • Loading branch information
oyvindberg authored Feb 16, 2020
2 parents 6f71d64 + d494532 commit e994542
Show file tree
Hide file tree
Showing 493 changed files with 5,676 additions and 5,294 deletions.
14 changes: 14 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ lazy val `importer-portable` = project
.dependsOn(ts, scalajs, phases)
.enablePlugins(BuildInfoPlugin)
.settings(
libraryDependencies ++= Seq(Deps.scalaXml),
buildInfoPackage := "org.scalablytyped.converter.internal",
buildInfoKeys := Seq[BuildInfoKey](
"gitSha" -> "git rev-parse -1 HEAD".!!.split("\n").last.trim,
Expand Down Expand Up @@ -105,6 +106,19 @@ lazy val baseSettings: Project => Project =
"-Xfatal-warnings",
),
)),
// scalacOptions ++= Seq(
// "-opt:l:inline",
// "-opt:l:method",
// "-opt:simplify-jumps",
// "-opt:compact-locals",
// "-opt:copy-propagation",
// "-opt:redundant-casts",
// "-opt:box-unbox",
// "-opt:nullness-tracking",
// "-opt:closure-invocations",
// "-opt-inline-from:**",
// "-opt-warnings",
// ),
/* disable scaladoc */
sources in (Compile, doc) := Nil,
publishArtifact in (Compile, packageDoc) := false,
Expand Down
35 changes: 18 additions & 17 deletions docs/devel/running.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,24 @@ For development you'll always use "debug mode".

| option | description |
| --- | --- |
| `-conserveSpace` | The CI server (and perhaps your developer laptop) doesn't have much hard drive space. This thins out the `node_modules` folder resulting from installing all the libraries outside DefinitelyTyped and keeps only what we need
| `-debugMode` | Force debugMode
| `-demoSet` | Adds the set of all libraries used in the [demos](https://github.com/oyvindberg/ScalablyTypedDemos/)
| `-dontCleanProject` | Normally the CI build aggressively resets the ScalablyTyped git repo. Enabling this will skip that
| `-enableParseCache` | The Typescript parser is somewhat slow. Enabling this uses java serialization to cache when possible
| `-forceCommit` | Commit and build sbt plugin in debug mode
| `-nextVersions` | Build libraries with Scala.js 1.0.0-RC2 instead
| `-offline` | Skip pulling newest DefinitelyTyped and running `npm update`
| `-pedantic` | Make the converter more strict. Most things don't work yet in this mode
| `-publish` | Publish to bintray. You'll need credentials in `~/.bintray/.credentials`
| `-sequential` | We have some [issues](https://github.com/oyvindberg/ScalablyTypedConverter/issues/74) with parallel conversion. For now it's a must for consistent CI builds
| `-softWrites` | Will only write changed/deleted files. This is essential if you want to keep ScalablyTyped products open in an IDE to avoid reindexing the world.
| `-flavourPlain` | Don't generate companion objects, react components and so on. Fastest.
| `-flavourNormal` | (default, but need to specify if you want more flavours).
| `-flavourSlinky` | Use slinky flavour, integrate with scalajs-dom, and generate slinky components
| `-flavourJapgolly` | Use scalajs-react flavour, integrate with scalajs-dom, and generate scalajs-react components
| `-conserveSpace` | The CI server (and perhaps your developer laptop) doesn't have much hard drive space. This thins out the `node_modules` folder resulting from installing all the libraries outside DefinitelyTyped and keeps only what we need
| `-debugMode` | Force debugMode
| `-demoSet` | Adds the set of all libraries used in the [demos](https://github.com/oyvindberg/ScalablyTypedDemos/)
| `-dontCleanProject` | Normally the CI build aggressively resets the ScalablyTyped git repo. Enabling this will skip that
| `-enableParseCache` | The Typescript parser is somewhat slow. Enabling this uses java serialization to cache when possible
| `-forceCommit` | Commit and build sbt plugin in debug mode
| `-scala212` | Build libraries with Scala 2.12 instead of 2.13
| `-scalajs1` | Build libraries with Scala.js 1 instead of 0.6
| `-offline` | Skip pulling newest DefinitelyTyped and running `npm update`
| `-parallel` | Faster, but with some [issues](https://github.com/oyvindberg/ScalablyTypedConverter/issues/74). May deadlock or produce unrepeatable builds for now
| `-pedantic` | Make the converter more strict. Most things don't work yet in this mode
| `-publish` | Publish to bintray. You'll need credentials in `~/.bintray/.credentials`
| `-softWrites` | Will only write changed/deleted files. This is essential if you want to keep ScalablyTyped products open in an IDE to avoid reindexing the world.
| `-flavourNormal` | default
| `-flavourSlinky` | Use slinky flavour, integrate with scalajs-dom, and generate slinky components
| `-flavourJapgolly` | Use scalajs-react flavour, integrate with scalajs-dom, and generate scalajs-react components
| `-useScalaJsDomTypes` | Rewrite types to use scala-js-dom types when using `-flavourNormal`

### Directories
By default, all files will be written to `~/tmp/tso-cache`. The only exception is the ivy artifacts, which are local-published
By default, all files will be written to `~/.cache/scalablytyped`. The only exception is the ivy artifacts, which are local-published
to `~/.ivy2/local`.
131 changes: 42 additions & 89 deletions docs/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Getting started - SBT plugin
---

The plugin uses [scalajs-bundler](https://scalacenter.github.io/scalajs-bundler/)
to download NPM packages, and translates typescript type definitions into Scala.js before your project compiles, as an SBT source generator.
to download NPM packages, and translates typescript type definitions into Scala.js jars before your project compiles.

If you for some reason cannot use scalajs-bundler, there is a more general version [here](plugin-no-bundler.md).

Expand All @@ -13,7 +13,7 @@ If you for some reason cannot use scalajs-bundler, there is a more general versi
Then check out the demo projects:
- [Demos](https://github.com/ScalablyTyped/Demos)
- [React/Slinky demos](https://github.com/ScalablyTyped/SlinkyDemos)
- `Scalajs-React demos` (we need help porting slinky demos!)
- `Scalajs-React demos` (help wanted!)

# Setup

Expand All @@ -22,9 +22,8 @@ Then check out the demo projects:
Due to conflicting scala library dependencies **this plugin needs sbt 1.3.0 or newer**.

Since we generate source code, it should work with any combination of
Scala 2.12/2.13 and Scala.js 0.6.x/1.0.0-milestones.
Certain [flavour](flavour.md)s might not yet work on Scala.js 1.0.0 milestones
if the libraries have not been published.
Scala 2.12 / 2.13 and Scala.js 1 / 0.6.
Certain [flavours](flavour.md) might not yet work on Scala.js 1 if the libraries have not been published.

## Add to your `project/plugins.sbt`

Expand Down Expand Up @@ -85,112 +84,71 @@ project.settings(
)
```

## Make it faster (Optional)
## Use yarn instead of npm

You'll notice that your build is now slow.

This part will walk you through how to speed it up within the build.
Keep in mind that you can always pull the code generation and compilation up into a dependency
that you build independently if any of this becomes a showstopper.

Your build is now slow because of three things, which we'll handle in turn.

### `npmInstall`

The first thing you should do is to configure scalajs-bundler to use yarn:
The plugin checks for updated npm dependencies on each compile, and yarn responds much faster than npm.

Configure scalajs-bundler like this:
```scala
project.settings(
useYarn := true
)
```
Yarn will need to be present on your system for this to work. You should also check in `yarn.lock`.
The main reason we do that is that `npm` uses seconds to verify that everything is current, and that will
be done for **every** compile.

### `stIgnore`
ScalablyTypedConverter is not that fast yet. Surely there are low hanging fruits for speeding it up,
but we're following an old development [mantra](https://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast).

The most important way to speed it up is to make it do less work. Enter `stIgnore`.
## How it works

So what can we ignore?
Hopefully everything will work automatically. Change an npm dependency, reimport project, wait, voila.

Let's take a few examples:

- `csstype` is a type-only library from DefinitelyTyped which describes all of react CSS with Typescript interfaces, enabling
type-safe use. It is a dependency of `react`, and used throughout that ecosystem.
This is something you either want, or don't care about. If you don't, you can exclude it like this:
The plugin taps into the `unmanagedJars` task in sbt, and this has some consequences for how it works.
Whenever the task is evaluated, typically through a `compile` or an import into an IDE, the plugin

```scala
project.settings(
Compile / stIgnore += "csstype"
)
```
- Runs a customized version of `installNpmDependencies` from scalajs-bundler, changed to avoid touching `unmanagedJars`.

- Let's say you want to use an old version of `material-ui` which comes bundled with 5000 icons, modelled as react component classes.
You also don't need the icons. If that's the case, you can also exclude prefixes of module names with the same mechanism

```scala
project.settings(
Compile / stIgnore ++= List("material-ui/svg-icons")
)
```
- Computes a digest from the resulting `package.json` file and of the configuration of the plugin

### Compiling all that generated code
- If we have a stored conversion with the given digest and if all the generated artifacts exist locally, we return those

There may be a **lot**.
- Otherwise we run converter, compiling only the missing libraries if any. Libraries are also digested by their contents,
to avoid unnecessary recompilations.

Ignoring libraries or modules will help, but our main tool here is called `stMinimize`.
Importing a build with a configuration the machine has seen and compiled before should be very fast.

By minimization we mean to remove everything from a library except what is referenced from somewhere else, so that
things keep compiling.
## Customize the generated code

The point is that you typically want everything from your main libraries,
but you care less about their (transitive) dependencies.
### `stIgnore`
There are a few reasons you might want to ignore things:
- A dependency of a library you want to use might fail conversion/compilation and you can try to salvage the situation by ignoring it.
- A dependency is slow to convert/build and you have no use for it
- A library has a circular set of dependencies (it's javascript, of course it happens) you might break the circuit by ignoring a library.

Since you typically don't want to enumerate all transitive dependencies, the `Selection` helper type provided for this:
The consequence of ignoring a library is typically that whenever another library references something in it,
that reference will be translated as `js.Any` with a comment (and there will be warnings when importing).

- `Selection.None` disables for all libraries (default)
- `Selection.NoneExcept(String*)` enables only given libraries
- `Selection.All` enables for all libraries
- `Selection.AllExcept(String*)` enables only not given libraries (most useful)
You cannot ignore the `std` library.

Some usage examples:

Using that, typical usage of `stMinimize` looks like this:
- `csstype` is a type-only library from DefinitelyTyped which describes all of react CSS with Typescript interfaces, enabling
type-safe use. It is a dependency of `react`, and used throughout that ecosystem.
This is something you either want, or don't care about. If you don't, you can exclude it like this:

```scala
project.settings(
Compile / stMinimize := Selection.AllExcept("axios", "material-ui", "mobx-react", "mobx")
Compile / stIgnore += "csstype"
)
```

Note that if you use a [react flavour](flavour.md) which generates a `components` package, all those
components are considered "entry points", and are not eligible for removal.
In other words, if you use **only** react components from a library, it's fine to minimize that, too.
```

### `stMinimizeKeep`
If you want to just keep a few things from a library and minimize away the rest, there is also a mechanism for that.
The names you supply should be exactly as they appear in the generated scala code without the initial package prefix (typically `typings`).
- Let's say you want to use an old version of `material-ui` which comes bundled with 5000 icons, modelled as react component classes.
You also don't need the icons. If that's the case, you can also exclude prefixes of module names with the same mechanism

```scala
project.settings(
/* setup libraries */
Compile / npmDependencies ++= Seq(
"moment" -> "2.24.0",
"react-big-calendar" -> "0.22",
"@types/react-big-calendar" -> "0.22.3"
),
/* say we want to minimize all */
Compile / stMinimize := Selection.All,
/* but keep these very specific things*/
Compile / stMinimizeKeep ++= List(
"moment.mod.^",
"reactBigCalendar.mod.momentLocalizer",
"reactBigCalendar.mod.View",
),
Compile / stIgnore ++= List("material-ui/svg-icons")
)
```

```
## Customize the generated code
### `stEnableScalaJsDefined`

As explained in the corresponding [Scala.js documentation page](http://www.scala-js.org/doc/interoperability/sjs-defined-js-classes.html),
Expand Down Expand Up @@ -229,9 +187,7 @@ Also note that if you use a [flavour](flavour.md) which translates types to `sca
only types found in the chosen stdlib will be translated.

### `stOutputPackage`
For aesthetic reasons, or because you want to shade the typings in a new package
if you're building a library, you can adjust the top-level package into which
we put the generated code.
You can adjust the top-level package into which we put the generated code.

```scala
project.settings(
Expand Down Expand Up @@ -262,13 +218,10 @@ Do you find the debug output tiring?
Global / stQuiet := true
```

By default we cache the results of the parser, since it needs to be rewritten to be fast.
The results is shared by default in `~/.cache/scalablytyped-sbt`.
By default we store caches and built artifacts in `~/.cache/scalablytyped`.

If you want to disable caching for some reason or change location you can set
If that doesn't suit you, you can specify another directory

```scala
Global / stCacheDir := Some(file("/some/other/dir"))

Global / stCacheDir := None // disables cache
Global / stDir := file("/some/other/dir")
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.scalablytyped.converter.internal.importer

import org.scalablytyped.converter.Selection
import org.scalablytyped.converter.internal.ts.{TsIdentLibrary, TsIdentLibraryScoped, TsIdentLibrarySimple}

object EnabledTypeMappingExpansion {
val DefaultSelection: Selection[TsIdentLibrary] =
Selection.NoneExcept(
TsIdentLibrary("amap-js-api"),
TsIdentLibrary("antd"),
TsIdentLibrary("instagram-private-api"),
TsIdentLibrary("jest-config"),
TsIdentLibrary("react-autosuggest"),
TsIdentLibrary("react-dropzone"),
TsIdentLibrary("react-native"),
TsIdentLibrary("react-onsenui"),
TsIdentLibrary("react-select"),
TsIdentLibraryScoped("ant-design", "colors"),
TsIdentLibraryScoped("ant-design", "create-react-context"),
TsIdentLibraryScoped("ant-design", "dark-theme"),
TsIdentLibraryScoped("ant-design", "icons"),
TsIdentLibraryScoped("ant-design", "icons-angular"),
TsIdentLibraryScoped("ant-design", "icons-react"),
TsIdentLibraryScoped("ant-design", "icons-react-native"),
TsIdentLibraryScoped("ant-design", "icons-vue"),
TsIdentLibraryScoped("ant-design", "pro-layout"),
TsIdentLibraryScoped("ant-design", "react-native"),
TsIdentLibraryScoped("material-ui", "core"),
TsIdentLibraryScoped("material-ui", "icons"),
TsIdentLibraryScoped("material-ui", "lab"),
TsIdentLibraryScoped("material-ui", "system"),
TsIdentLibraryScoped("material-ui", "utils"),
TsIdentLibraryScoped("nivo", "annotations"),
TsIdentLibraryScoped("nivo", "axes"),
TsIdentLibraryScoped("nivo", "bar"),
TsIdentLibraryScoped("nivo", "bullet"),
TsIdentLibraryScoped("nivo", "calendar"),
TsIdentLibraryScoped("nivo", "chord"),
TsIdentLibraryScoped("nivo", "circle-packing"),
TsIdentLibraryScoped("nivo", "colors"),
TsIdentLibraryScoped("nivo", "core"),
TsIdentLibraryScoped("nivo", "generators"),
TsIdentLibraryScoped("nivo", "geo"),
TsIdentLibraryScoped("nivo", "heatmap"),
TsIdentLibraryScoped("nivo", "legends"),
TsIdentLibraryScoped("nivo", "line"),
TsIdentLibraryScoped("nivo", "parallel-coordinates"),
TsIdentLibraryScoped("nivo", "pie"),
TsIdentLibraryScoped("nivo", "radar"),
TsIdentLibraryScoped("nivo", "sankey"),
TsIdentLibraryScoped("nivo", "scales"),
TsIdentLibraryScoped("nivo", "scatterplot"),
TsIdentLibraryScoped("nivo", "stream"),
TsIdentLibraryScoped("nivo", "sunburst"),
TsIdentLibraryScoped("nivo", "tooltip"),
TsIdentLibraryScoped("nivo", "treemap"),
TsIdentLibraryScoped("nivo", "voronoi"),
TsIdentLibraryScoped("nivo", "waffle"),
TsIdentLibraryScoped("react-navigation", "core"),
TsIdentLibraryScoped("react-navigation", "native"),
TsIdentLibraryScoped("tensorflow", "tfjs"),
TsIdentLibraryScoped("tensorflow", "tfjs-converter"),
TsIdentLibraryScoped("tensorflow", "tfjs-core"),
TsIdentLibraryScoped("tensorflow", "tfjs-data"),
TsIdentLibraryScoped("tensorflow", "tfjs-layers"),
TsIdentLibraryScoped("tensorflow", "tfjs-node"),
TsIdentLibraryScoped("uifabric", "foundation"),
TsIdentLibraryScoped("uifabric", "icons"),
TsIdentLibraryScoped("uifabric", "merge-styles"),
TsIdentLibraryScoped("uifabric", "react-hooks"),
TsIdentLibraryScoped("uifabric", "set-version"),
TsIdentLibraryScoped("uifabric", "styling"),
TsIdentLibraryScoped("uifabric", "utilities"),
TsIdentLibrarySimple("react-navigation"),
TsIdentLibrarySimple("react-navigation-drawer"),
TsIdentLibrarySimple("react-navigation-material-bottom-tabs"),
TsIdentLibrarySimple("react-navigation-stack"),
TsIdentLibrary("@storybook/api"),
TsIdentLibrary("styled-components"),
)
}
Loading

0 comments on commit e994542

Please sign in to comment.