Skip to content

Commit

Permalink
Canonical of BUILD file generation for JavaScript and TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
gregmagolan committed Nov 1, 2022
1 parent 66df174 commit c538cdf
Show file tree
Hide file tree
Showing 37 changed files with 881 additions and 0 deletions.
4 changes: 4 additions & 0 deletions js_build_file_generation/.bazelignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
apps/triad/node_modules
libs/rune/node_modules
packages/iris/node_modules
1 change: 1 addition & 0 deletions js_build_file_generation/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test --test_output=errors
1 change: 1 addition & 0 deletions js_build_file_generation/.bazelversion
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6.0.0rc1
36 changes: 36 additions & 0 deletions js_build_file_generation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# compiled output
dist
node_modules
bazel-*

# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
6 changes: 6 additions & 0 deletions js_build_file_generation/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Disabling pnpm [hoisting](https://pnpm.io/npmrc#hoist) by setting `hoist=false` is recommended on
# projects using rules_js so that pnpm outside of Bazel lays out a node_modules tree similar to what
# rules_js lays out under Bazel (without a hidden node_modules/.pnpm/node_modules). See
# https://github.com/aspect-build/rules_js/blob/7377f2d0387cc2a9251137929b1c53ccdb3fbcf0/docs/npm_import.md#npm_translate_lock
# documentation for more information.
hoist=false
25 changes: 25 additions & 0 deletions js_build_file_generation/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@aspect_rules_ts//ts:defs.bzl", "ts_config")

npm_link_all_packages()

# 💁 A tsconfig target to be used in ts_project targets throughout the monorepo.
#
# 💡 DESIGN: This seems like unnecessary boilerplate and by default we could just generate an sane
# default tsconfig in each ts_project target with sane defaults such as `declaration = True`
ts_config(
name = "tsconfig",
src = "tsconfig.json",
visibility = ["//visibility:public"],
)

# 💁 A jest config target to be used in jest_target targets throughout the monorepo.
#
# 💡 DESIGN: This seems like unnecessary boilerplate and by default we could just generate an empty
# jest config in jest_test by default.
js_library(
name = "jest_config",
srcs = ["jest.config.js"],
visibility = ["//visibility:public"],
)
33 changes: 33 additions & 0 deletions js_build_file_generation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Canonical of BUILD file generation for JavaScript and TypeScript

Example monorepo example that is structured for JavaScript and TypeScript BUILD
file generation using the Aspect CLI.

Library, feature and app names were generated with https://www.fantasynamegenerators.com/software-names.php

## Structure

Sources in this monorepo example is structured into three top-level folders:

- apps: Applications
- libs: Shared libraries that are not linked but imported via relative paths `../../libs/foo`
- packages: Shared code that is consumed via named links and imported from node_modules `@example/foo`

Using bazel query to list all of the targets in the repository is a quick way to see they monorepo structure:

```
bazel query ... | grep -v node_modules | grep -v _validate
//:tsconfig
//apps/triad:triad
//apps/triad:triad_lib
//apps/triad/pivot:pivot
//apps/triad/vibe:vibe
//libs/rune/asap:asap
//libs/rune/rebus:rebus
//packages/iris:iris
//packages/iris:iris_lib
//packages/iris/abra:abra
//packages/iris/pitch:pitch
```

(we filter out "node_modules" and typescript boilerplate targets "_validate" targets)
61 changes: 61 additions & 0 deletions js_build_file_generation/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
name = "aspect_rules_js",
sha256 = "d8eabcd1e05d93147505ea806fa21089926b771d8813f01b92af5dec36617033",
strip_prefix = "rules_js-1.6.3",
url = "https://github.com/aspect-build/rules_js/archive/refs/tags/v1.6.3.tar.gz",
)

http_archive(
name = "aspect_rules_ts",
sha256 = "1149d4cf7f210de67e0fc5cd3e8f624de3ee976ac05af4f1484e57a74c12f2dc",
strip_prefix = "rules_ts-1.0.0-rc5",
url = "https://github.com/aspect-build/rules_ts/archive/refs/tags/v1.0.0-rc5.tar.gz",
)

http_archive(
name = "aspect_rules_jest",
sha256 = "bb3226707f9872185865a6381eb3a19311ca7b46e8ed475aad50975906a6cb6a",
strip_prefix = "rules_jest-0.10.0",
url = "https://github.com/aspect-build/rules_jest/archive/refs/tags/v0.10.0.tar.gz",
)

load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies")

rules_js_dependencies()

load("@aspect_rules_ts//ts:repositories.bzl", "rules_ts_dependencies", LATEST_TS_VERSION = "LATEST_VERSION")

rules_ts_dependencies(ts_version = LATEST_TS_VERSION)

load("@aspect_rules_jest//jest:dependencies.bzl", "rules_jest_dependencies")

rules_jest_dependencies()

# Fetches the npm packages for jest-cli.
load("@aspect_rules_jest//jest:repositories.bzl", "LATEST_VERSION", "jest_repositories")

jest_repositories(
name = "jest",
jest_version = LATEST_VERSION,
)

load("@rules_nodejs//nodejs:repositories.bzl", "DEFAULT_NODE_VERSION", "nodejs_register_toolchains")

nodejs_register_toolchains(
name = "nodejs",
node_version = DEFAULT_NODE_VERSION,
)

load("@aspect_rules_js//npm:npm_import.bzl", "npm_translate_lock")

npm_translate_lock(
name = "npm",
pnpm_lock = "//:pnpm-lock.yaml",
verify_node_modules_ignored = "//:.bazelignore",
)

load("@npm//:repositories.bzl", "npm_repositories")

npm_repositories()
41 changes: 41 additions & 0 deletions js_build_file_generation/apps/triad/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_library")
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
load("@npm//:defs.bzl", "npm_link_all_packages")

# 💁 Creates the npm package targets in the package to depend on. Together these targets constitute
# the "node_modules" folder in the output tree.
npm_link_all_packages()

ts_project(
name = "triad_ts",
srcs = [
"main.ts",
],
declaration = True,
tsconfig = "//:tsconfig",
deps = [
"//apps/triad/pivot",
"//apps/triad/vibe",
],
)

js_library(
name = "triad_lib",
srcs = [
"package.json",
":triad_ts",
],
)

# 💁 A binary target to run the built application in this package.
#
# 💡 DESIGN: How does the BUILD file generator determine what package should have a js_binary
# target? golang knows because the package name is "main" and the entry point is a "main" function.
# No such convention in js.
js_binary(
name = "triad",
data = [
":triad_lib",
],
entry_point = "main.js",
)
7 changes: 7 additions & 0 deletions js_build_file_generation/apps/triad/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { name as vibeName, info as vibeInfo } from './vibe';
import { name as pivotName } from './pivot';

console.log('-Triad-');
console.log(vibeName());
console.log(vibeInfo());
console.log(pivotName());
6 changes: 6 additions & 0 deletions js_build_file_generation/apps/triad/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"dependencies": {
"chalk": "5.0.1",
"@example/iris": "workspace:*"
}
}
10 changes: 10 additions & 0 deletions js_build_file_generation/apps/triad/pivot/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")

js_library(
name = "pivot",
srcs = [
"index.d.ts",
"index.js",
],
visibility = ["//visibility:public"],
)
1 change: 1 addition & 0 deletions js_build_file_generation/apps/triad/pivot/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare function name(): string;
5 changes: 5 additions & 0 deletions js_build_file_generation/apps/triad/pivot/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
name: function () {
return 'pivot';
},
};
23 changes: 23 additions & 0 deletions js_build_file_generation/apps/triad/vibe/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
load("@aspect_rules_js//js:defs.bzl", "js_library")

ts_project(
name = "vibe_ts",
srcs = [
"index.ts",
],
declaration = True,
tsconfig = "//:tsconfig",
deps = [
"//apps/triad:node_modules/@example/iris",
"//libs/rune/asap",
],
)

js_library(
name = "vibe",
srcs = [
":vibe_ts",
],
visibility = ["//visibility:public"],
)
10 changes: 10 additions & 0 deletions js_build_file_generation/apps/triad/vibe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { pitchName } from '@example/iris';
import { name as asapName } from '../../../libs/rune/asap';

export function name(): string {
return 'vibe';
}

export function info(): string[] {
return [pitchName(), asapName()];
}
1 change: 1 addition & 0 deletions js_build_file_generation/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
3 changes: 3 additions & 0 deletions js_build_file_generation/libs/rune/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
load("@npm//:defs.bzl", "npm_link_all_packages")

npm_link_all_packages()
10 changes: 10 additions & 0 deletions js_build_file_generation/libs/rune/asap/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")

js_library(
name = "asap",
srcs = [
"index.d.ts",
"index.js",
],
visibility = ["//visibility:public"],
)
1 change: 1 addition & 0 deletions js_build_file_generation/libs/rune/asap/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare function name(): string;
5 changes: 5 additions & 0 deletions js_build_file_generation/libs/rune/asap/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
name: function () {
return 'asap';
},
};
5 changes: 5 additions & 0 deletions js_build_file_generation/libs/rune/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"uuid": "9.0.0"
}
}
70 changes: 70 additions & 0 deletions js_build_file_generation/libs/rune/rebus/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
load("@jest//jest:defs.bzl", "jest_test")

# 💁 A TypeScript transpilation and type check target. This target type checks TypesScript files and
# generates JavaScript and declaration files that are to be included in the "library" target for
# this package.
ts_project(
name = "rebus_ts",
srcs = [
"index.ts",
],
declaration = True,
tsconfig = "//:tsconfig",
)

# 💁 A JavaScript "library" target. This target includes .js files from transpilation targets and
# any other files to that make up the JavaScript "library". This typically includes all `.js`,
# `.d.ts` and `.json` files in the package. Additional file types and include/exclude patterns
# should be configurable with Aspect CLI directives.
#
# 💡 DESIGN: do we always stamp out a js_library target even if there are no additional files to
# include besides the outputs of the ts target? My feeling is yes and that is it better for
# consistency and and readability. If additional files are added to the package after the initial
# generation then a new does target does _not_ need to stamped out.
js_library(
name = "rebus",
srcs = [
":rebus_ts",
],
visibility = ["//visibility:public"],
)

# 💁 A TypeScript transpilation and type check target for *.spec.ts and *.test.ts files. This target
# type checks TypesScript files and generates JavaScript and declaration files that are to be
# included in the test "library" target for this package.
ts_project(
name = "rebus_test_ts",
srcs = [
"index.spec.ts",
],
declaration = True,
tsconfig = "//:tsconfig",
deps = [
":rebus",
"//:node_modules/@types/jest",
"//:node_modules/@types/node",
],
)

# 💁 A JavaScript test "library" target. This target includes .js spec & test files from
# transpilation targets and any other files to that make up the JavaScript test "library".
js_library(
name = "rebus_test_lib",
srcs = [
":rebus",
":rebus_test_ts",
],
)

# 💁 A test target to test all spec & test files in this package
#
# 💡 DESIGN: The BUILD file generator should default to jest since it is simple and robust but
# should be configurable to use a different test target type provided it has similar semantics
# of runfiles being provided via data.
jest_test(
name = "rebus_test",
config = "//:jest_config",
data = [":rebus_test_lib"],
)
5 changes: 5 additions & 0 deletions js_build_file_generation/libs/rune/rebus/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { name } from './index';

test('rebus', () => {
expect(name()).toBe('rebus');
});
3 changes: 3 additions & 0 deletions js_build_file_generation/libs/rune/rebus/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function name(): string {
return 'rebus';
}
Loading

0 comments on commit c538cdf

Please sign in to comment.