Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Compile dependencies from node_modules #732

Draft
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions samples/kotlin-js-store/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"

"@js-joda/[email protected]":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273"
integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==

"@leichtgewicht/ip-codec@^2.0.1":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
Expand Down Expand Up @@ -851,6 +856,14 @@ dom-serialize@^2.2.1:
extend "^3.0.0"
void-elements "^2.0.0"

[email protected]:
version "0.5.8-rc.4"
resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21"
integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA==
dependencies:
google-protobuf "3.12.2"
typescript "3.9.5"

[email protected]:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
Expand Down Expand Up @@ -1212,6 +1225,11 @@ glob@^7.1.3, glob@^7.1.7:
once "^1.3.0"
path-is-absolute "^1.0.0"

[email protected]:
version "3.12.2"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53"
integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA==

graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
Expand Down Expand Up @@ -2437,6 +2455,11 @@ type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"

[email protected]:
version "3.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==

ua-parser-js@^0.7.30:
version "0.7.31"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
Expand Down
1 change: 1 addition & 0 deletions samples/world-clock/presenters/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ kotlin {
val commonMain by getting {
dependencies {
api("app.cash.zipline:zipline")
api("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") // TODO gradle/libs.versions.toml
}
}
val hostMain by creating {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package app.cash.zipline.samples.worldclock

import app.cash.zipline.ZiplineService
import kotlinx.coroutines.flow.Flow
import kotlinx.datetime.TimeZone
import kotlinx.serialization.Serializable

@Serializable
Expand All @@ -29,10 +30,16 @@ data class WorldClockModel(
val label: String,
)

@Serializable
data class TimeZoneModel(
val name: String,
val zone: TimeZone,
)

interface WorldClockPresenter : ZiplineService {
fun models(events: Flow<WorldClockEvent>): Flow<WorldClockModel>
}

interface WorldClockHost : ZiplineService {
fun timeZones(): List<String>
fun timeZones(): List<TimeZoneModel>
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@
*/
package app.cash.zipline.samples.worldclock

import kotlinx.datetime.TimeZone

class RealWorldClockHost : WorldClockHost {
override fun timeZones(): List<String> {
TODO()
override fun timeZones(): List<TimeZoneModel> {
return listOf(
TimeZoneModel("Barcelona", TimeZone.of("CEST")),
TimeZoneModel("NYC", TimeZone.of("EST")),
TimeZoneModel("SF", TimeZone.of("PST")),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,23 @@
package app.cash.zipline.samples.worldclock

import kotlin.js.Date
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.toLocalDateTime

class TimeFormatter {
fun format(
timestamp: Instant = Clock.System.now(),
timeZones: List<TimeZoneModel>,
): String {
return timeZones.joinToString("\n\n") {
"""
|${it.name}
|${timestamp.toLocalDateTime(it.zone)}
""".trimMargin()
}
}

fun formatLocalTime(
now: dynamic = Date(),
millis: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class RealWorldClockPresenter(
while (true) {
emit(
WorldClockModel(
label = TimeFormatter().formatLocalTime()
label = TimeFormatter().format(timeZones = host.timeZones())
)
)
delay(16)
Expand Down
1 change: 1 addition & 0 deletions zipline-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.vanniktech.maven.publish.MavenPublishBaseExtension
plugins {
id("java-gradle-plugin")
kotlin("jvm")
kotlin("plugin.serialization")
id("com.github.gmazzo.buildconfig")
id("org.jetbrains.dokka")
id("com.vanniktech.maven.publish.base")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ abstract class ZiplineCompileTask : DefaultTask() {
@get:OutputDirectory
abstract val outputDir: DirectoryProperty

@get:Optional
@get:InputDirectory
abstract val nodeModuleDir: DirectoryProperty

@get:Optional
@get:Input
abstract val mainModuleId: Property<String>
Expand All @@ -65,6 +69,7 @@ abstract class ZiplineCompileTask : DefaultTask() {
fun task(inputChanges: InputChanges) {
val inputDirFile = inputDir.get().asFile
val outputDirFile = outputDir.get().asFile
val nodeModuleDirFile = nodeModuleDir.orNull?.asFile
val mainModuleId = mainModuleId.orNull
val mainFunction = mainFunction.orNull
val signingKeys = signingKeys.get()
Expand Down Expand Up @@ -101,6 +106,7 @@ abstract class ZiplineCompileTask : DefaultTask() {
ZiplineCompiler.compile(
inputDir = inputDirFile,
outputDir = outputDirFile,
nodeModulesDir = nodeModuleDirFile,
mainFunction = mainFunction,
mainModuleId = mainModuleId,
manifestSigner = manifestSigner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package app.cash.zipline.gradle

import app.cash.zipline.QuickJs
import app.cash.zipline.bytecode.applySourceMapToBytecode
import app.cash.zipline.gradle.internal.NpmPackage
import app.cash.zipline.loader.CURRENT_ZIPLINE_VERSION
import app.cash.zipline.loader.ManifestSigner
import app.cash.zipline.loader.ZiplineFile
Expand All @@ -40,16 +41,22 @@ internal object ZiplineCompiler {
private const val MODULE_PATH_PREFIX = "./"
private const val ZIPLINE_EXTENSION = ".zipline"

private val npmPackageJson = Json { ignoreUnknownKeys = true }

fun compile(
inputDir: File,
outputDir: File,
nodeModulesDir: File?,
mainFunction: String?,
mainModuleId: String?,
manifestSigner: ManifestSigner?,
version: String?,
) {
val jsFiles = getJsFiles(inputDir.listFiles()!!.asList())
val modules = compileFilesInParallel(jsFiles, outputDir)
var modules = compileFilesInParallel(jsFiles, outputDir)
if (nodeModulesDir != null) {
modules = compileNodeModules(modules, nodeModulesDir, outputDir)
}
writeManifest(
outputDir = outputDir,
mainFunction = mainFunction,
Expand All @@ -70,6 +77,7 @@ internal object ZiplineCompiler {
manifestSigner: ManifestSigner?,
version: String?,
) {
// TODO support node_modules resolution
val modifiedFileNames = getJsFiles(modifiedFiles).map { it.name }.toSet()
val removedFileNames = getJsFiles(removedFiles).map { it.name }.toSet()

Expand Down Expand Up @@ -113,6 +121,29 @@ internal object ZiplineCompiler {
.toMap()
}

private fun compileNodeModules(
modules: Map<String, ZiplineManifest.Module>,
nodeModulesDir: File,
outputDir: File,
): Map<String, ZiplineManifest.Module> {
val allModules = modules.toMutableMap()
val dependencies = ArrayDeque(allModules.values.flatMap { it.dependsOnIds })
while (dependencies.isNotEmpty()) {
val dependency = dependencies.removeFirst()
if (dependency !in allModules) {
// TODO is `main` the right property to be reading?
val dependencyDir = nodeModulesDir.resolve(dependency)
val packageJson = dependencyDir.resolve("package.json")
val npmPackage = npmPackageJson.decodeFromString<NpmPackage>(packageJson.readText())
val jsFile = dependencyDir.resolve(npmPackage.main ?: TODO())
val (_, module) = compileSingleFile(jsFile, outputDir)
allModules[dependency] = module
dependencies.addAll(module.dependsOnIds)
}
}
return allModules
}

private fun compileSingleFile(
jsFile: File,
outputDir: File,
Expand Down Expand Up @@ -189,10 +220,12 @@ fun main(vararg args: String) {

val inputDir = File(argsList.removeFirst())
val outputDir = File(argsList.removeFirst())
val nodeModulesDir = argsList.removeFirstOrNull()?.let { File(it) } // TODO new required argument?
outputDir.mkdirs()
ZiplineCompiler.compile(
inputDir = inputDir,
outputDir = outputDir,
nodeModulesDir = nodeModulesDir,
mainFunction = argsList.removeFirstOrNull(),
mainModuleId = argsList.removeFirstOrNull(),
manifestSigner = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import org.jetbrains.kotlin.gradle.targets.js.ir.JsIrBinary
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask
import org.slf4j.LoggerFactory

@Suppress("unused") // Created reflectively by Gradle.
Expand Down Expand Up @@ -67,6 +68,9 @@ class ZiplinePlugin : KotlinCompilerPluginSupportPlugin {
kotlinBinary: JsIrBinary,
configuration: ZiplineExtension,
) {
// TODO is this the best way to get the node_modules directory?
val npmInstallTask = project.rootProject.tasks.withType(KotlinNpmInstallTask::class.java).single()

// Like 'compileDevelopmentExecutableKotlinJsZipline'.
val linkTaskName = kotlinBinary.linkTaskName
val compileZiplineTaskName = "${linkTaskName}Zipline"
Expand All @@ -81,6 +85,7 @@ class ZiplinePlugin : KotlinCompilerPluginSupportPlugin {
createdTask.inputDir.fileProvider(linkOutputFolderProvider)
createdTask.outputDir.fileProvider(linkOutputFolderProvider.map { it.parentFile.resolve("${it.name}Zipline") })

createdTask.nodeModuleDir.fileValue(npmInstallTask.nodeModulesDir)
createdTask.mainModuleId.set(configuration.mainModuleId)
createdTask.mainFunction.set(configuration.mainFunction)
createdTask.version.set(configuration.version)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package app.cash.zipline.gradle.internal

import kotlinx.serialization.Serializable

@Serializable
internal data class NpmPackage(
val main: String?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class ZiplineCompilerTest {
ZiplineCompiler.compile(
inputDir = inputDir,
outputDir = outputDir,
nodeModulesDir = null, // TODO add node_modules test case
mainFunction = mainFunction,
mainModuleId = mainModuleId,
manifestSigner = null,
Expand Down