diff --git a/.bazelrc b/.bazelrc index b51cf1497f..aa0ee8d91f 100644 --- a/.bazelrc +++ b/.bazelrc @@ -5,8 +5,8 @@ import %workspace%/common.bazelrc # This lets us glob() up all the files inside the examples to make them inputs to tests # To update these lines, just run `yarn bazel:update-deleted-packages` # (Note, we cannot use common --deleted_packages because the bazel version command doesn't support it) -build --deleted_packages=examples/angular,examples/angular/e2e,examples/angular/src/app/home,examples/angular/src/app/hello-world,examples/angular/src/app,examples/angular/src/app/todos,examples/angular/src/app/todos/reducers,examples/angular/src/shared/material,examples/angular/src/lib/shorten,examples/angular/src,examples/angular/src/assets,examples/angular/tools,examples/angular_bazel_architect,examples/angular_bazel_architect/projects/frontend-lib,examples/angular_view_engine,examples/angular_view_engine/e2e,examples/angular_view_engine/src/app/home,examples/angular_view_engine/src/app/hello-world,examples/angular_view_engine/src/app,examples/angular_view_engine/src/app/todos,examples/angular_view_engine/src/app/todos/reducers,examples/angular_view_engine/src/shared/material,examples/angular_view_engine/src/lib/typography,examples/angular_view_engine/src/lib/shorten,examples/angular_view_engine/src,examples/angular_view_engine/src/assets,examples/app,examples/app/styles,examples/app/test,examples/closure,examples/create-react-app,examples/cypress,examples/from_source,examples/jest,examples/jest/ts/test,examples/jest/ts,examples/jest/ts/src,examples/kotlin,examples/nestjs,examples/nestjs/src,examples/parcel,examples/protocol_buffers,examples/react_webpack,examples/user_managed_deps,examples/vendored_node,examples/vendored_node_and_yarn,examples/vue,examples/vue/src,examples/web_testing,examples/webapp,examples/worker,e2e/bazel_managed_deps,e2e/concatjs_devserver,e2e/concatjs_devserver/genrule,e2e/concatjs_devserver/subpackage,e2e/coverage,e2e/fine_grained_symlinks,e2e/jasmine,e2e/node_loader_no_preserve_symlinks,e2e/node_loader_preserve_symlinks,e2e/nodejs_image,e2e/nodejs_image/foolib,e2e/packages,e2e/symlinked_node_modules_npm,e2e/symlinked_node_modules_yarn,e2e/typescript,e2e/webapp -query --deleted_packages=examples/angular,examples/angular/e2e,examples/angular/src/app/home,examples/angular/src/app/hello-world,examples/angular/src/app,examples/angular/src/app/todos,examples/angular/src/app/todos/reducers,examples/angular/src/shared/material,examples/angular/src/lib/shorten,examples/angular/src,examples/angular/src/assets,examples/angular/tools,examples/angular_bazel_architect,examples/angular_bazel_architect/projects/frontend-lib,examples/angular_view_engine,examples/angular_view_engine/e2e,examples/angular_view_engine/src/app/home,examples/angular_view_engine/src/app/hello-world,examples/angular_view_engine/src/app,examples/angular_view_engine/src/app/todos,examples/angular_view_engine/src/app/todos/reducers,examples/angular_view_engine/src/shared/material,examples/angular_view_engine/src/lib/typography,examples/angular_view_engine/src/lib/shorten,examples/angular_view_engine/src,examples/angular_view_engine/src/assets,examples/app,examples/app/styles,examples/app/test,examples/closure,examples/create-react-app,examples/cypress,examples/from_source,examples/jest,examples/jest/ts/test,examples/jest/ts,examples/jest/ts/src,examples/kotlin,examples/nestjs,examples/nestjs/src,examples/parcel,examples/protocol_buffers,examples/react_webpack,examples/user_managed_deps,examples/vendored_node,examples/vendored_node_and_yarn,examples/vue,examples/vue/src,examples/web_testing,examples/webapp,examples/worker,e2e/bazel_managed_deps,e2e/concatjs_devserver,e2e/concatjs_devserver/genrule,e2e/concatjs_devserver/subpackage,e2e/coverage,e2e/fine_grained_symlinks,e2e/jasmine,e2e/node_loader_no_preserve_symlinks,e2e/node_loader_preserve_symlinks,e2e/nodejs_image,e2e/nodejs_image/foolib,e2e/packages,e2e/symlinked_node_modules_npm,e2e/symlinked_node_modules_yarn,e2e/typescript,e2e/webapp +build --deleted_packages=examples/angular,examples/angular/e2e,examples/angular/src/app/home,examples/angular/src/app/hello-world,examples/angular/src/app,examples/angular/src/app/todos,examples/angular/src/app/todos/reducers,examples/angular/src/shared/material,examples/angular/src/lib/shorten,examples/angular/src,examples/angular/src/assets,examples/angular/tools,examples/angular_bazel_architect,examples/angular_bazel_architect/projects/frontend-lib,examples/angular_view_engine,examples/angular_view_engine/e2e,examples/angular_view_engine/src/app/home,examples/angular_view_engine/src/app/hello-world,examples/angular_view_engine/src/app,examples/angular_view_engine/src/app/todos,examples/angular_view_engine/src/app/todos/reducers,examples/angular_view_engine/src/shared/material,examples/angular_view_engine/src/lib/typography,examples/angular_view_engine/src/lib/shorten,examples/angular_view_engine/src,examples/angular_view_engine/src/assets,examples/app,examples/app/styles,examples/app/test,examples/closure,examples/create-react-app,examples/cypress,examples/esbuild,examples/esbuild/src,examples/from_source,examples/jest,examples/jest/ts/test,examples/jest/ts,examples/jest/ts/src,examples/kotlin,examples/nestjs,examples/nestjs/src,examples/parcel,examples/protocol_buffers,examples/react_webpack,examples/user_managed_deps,examples/vendored_node,examples/vendored_node_and_yarn,examples/vue,examples/vue/src,examples/web_testing,examples/webapp,examples/worker,e2e/bazel_managed_deps,e2e/concatjs_devserver,e2e/concatjs_devserver/genrule,e2e/concatjs_devserver/subpackage,e2e/coverage,e2e/fine_grained_symlinks,e2e/jasmine,e2e/node_loader_no_preserve_symlinks,e2e/node_loader_preserve_symlinks,e2e/nodejs_image,e2e/nodejs_image/foolib,e2e/packages,e2e/symlinked_node_modules_npm,e2e/symlinked_node_modules_yarn,e2e/typescript,e2e/webapp +query --deleted_packages=examples/angular,examples/angular/e2e,examples/angular/src/app/home,examples/angular/src/app/hello-world,examples/angular/src/app,examples/angular/src/app/todos,examples/angular/src/app/todos/reducers,examples/angular/src/shared/material,examples/angular/src/lib/shorten,examples/angular/src,examples/angular/src/assets,examples/angular/tools,examples/angular_bazel_architect,examples/angular_bazel_architect/projects/frontend-lib,examples/angular_view_engine,examples/angular_view_engine/e2e,examples/angular_view_engine/src/app/home,examples/angular_view_engine/src/app/hello-world,examples/angular_view_engine/src/app,examples/angular_view_engine/src/app/todos,examples/angular_view_engine/src/app/todos/reducers,examples/angular_view_engine/src/shared/material,examples/angular_view_engine/src/lib/typography,examples/angular_view_engine/src/lib/shorten,examples/angular_view_engine/src,examples/angular_view_engine/src/assets,examples/app,examples/app/styles,examples/app/test,examples/closure,examples/create-react-app,examples/cypress,examples/esbuild,examples/esbuild/src,examples/from_source,examples/jest,examples/jest/ts/test,examples/jest/ts,examples/jest/ts/src,examples/kotlin,examples/nestjs,examples/nestjs/src,examples/parcel,examples/protocol_buffers,examples/react_webpack,examples/user_managed_deps,examples/vendored_node,examples/vendored_node_and_yarn,examples/vue,examples/vue/src,examples/web_testing,examples/webapp,examples/worker,e2e/bazel_managed_deps,e2e/concatjs_devserver,e2e/concatjs_devserver/genrule,e2e/concatjs_devserver/subpackage,e2e/coverage,e2e/fine_grained_symlinks,e2e/jasmine,e2e/node_loader_no_preserve_symlinks,e2e/node_loader_preserve_symlinks,e2e/nodejs_image,e2e/nodejs_image/foolib,e2e/packages,e2e/symlinked_node_modules_npm,e2e/symlinked_node_modules_yarn,e2e/typescript,e2e/webapp # Mock versioning command to test the --stamp behavior build --workspace_status_command="echo BUILD_SCM_VERSION 1.2.3" diff --git a/WORKSPACE b/WORKSPACE index 73471aeb32..2609e4c8ec 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -129,6 +129,11 @@ browser_repositories( firefox = True, ) +# Setup esbuild dependencies +load("//packages/esbuild:esbuild_repo.bzl", "esbuild_dependencies") + +esbuild_dependencies() + # # Dependencies to run stardoc & generating documentation # diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index ccb04183bb..8df81d8e6b 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -81,6 +81,7 @@ rules_nodejs_docs( "Rollup": "//packages/rollup:README.md", "Terser": "//packages/terser:README.md", "TypeScript": "//packages/typescript:README.md", + "esbuild": "//packages/esbuild:README.md", }, tags = [ "fix-windows", diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index ca13a6630e..3291da917f 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -245,3 +245,13 @@ example_integration_test( ], owners = ["@alan-agius4"], ) + +example_integration_test( + name = "examples_esbuild", + timeout = "long", + npm_packages = { + "//packages/esbuild:npm_package": "@bazel/esbuild", + "//packages/typescript:npm_package": "@bazel/typescript", + }, + owners = ["@mattem"], +) diff --git a/examples/esbuild/.bazelignore b/examples/esbuild/.bazelignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/examples/esbuild/.bazelignore @@ -0,0 +1 @@ +node_modules diff --git a/examples/esbuild/.bazelrc b/examples/esbuild/.bazelrc new file mode 100644 index 0000000000..3431057af6 --- /dev/null +++ b/examples/esbuild/.bazelrc @@ -0,0 +1 @@ +import %workspace%/../../common.bazelrc diff --git a/examples/esbuild/BUILD.bazel b/examples/esbuild/BUILD.bazel new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/esbuild/WORKSPACE b/examples/esbuild/WORKSPACE new file mode 100644 index 0000000000..0600a66d8f --- /dev/null +++ b/examples/esbuild/WORKSPACE @@ -0,0 +1,76 @@ +# Copyright 2019 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +workspace( + name = "examples_esbuild", + managed_directories = {"@npm": ["node_modules"]}, +) + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "build_bazel_rules_nodejs", + sha256 = "6142e9586162b179fdd570a55e50d1332e7d9c030efd853453438d607569721d", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.0.0/rules_nodejs-3.0.0.tar.gz"], +) + +http_archive( + name = "bazel_skylib", + sha256 = "afbe4d9d033c007940acd24bb9becf1580a0280ae0b2ebbb5a7cb12912d2c115", + strip_prefix = "bazel-skylib-ffad33e9bfc60bdfa98292ca655a4e7035792046", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/archive/ffad33e9bfc60bdfa98292ca655a4e7035792046.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/archive/ffad33e9bfc60bdfa98292ca655a4e7035792046.tar.gz", + ], +) + +_ESBUILD_VERSION = "0.8.34" + +http_archive( + name = "esbuild_darwin", + build_file_content = """exports_files(["bin/esbuild"])""", + sha256 = "3bf980b5175df873dd84fd614d57722f3b1b9c7e74929504e26192d23075d5c3", + strip_prefix = "package", + urls = [ + "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-%s.tgz" % _ESBUILD_VERSION, + ], +) + +http_archive( + name = "esbuild_windows", + build_file_content = """exports_files(["esbuild.exe"])""", + sha256 = "826cd58553e7b6910dd22aba001cd72af34e05c9c3e9af567b5b2a6b1c9f3941", + strip_prefix = "package", + urls = [ + "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-%s.tgz" % _ESBUILD_VERSION, + ], +) + +http_archive( + name = "esbuild_linux", + build_file_content = """exports_files(["bin/esbuild"])""", + sha256 = "9dff3f5b06fd964a1cbb6aa9ea5ebf797767f1bd2bac71e084fb0bbefeba24a3", + strip_prefix = "package", + urls = [ + "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-%s.tgz" % _ESBUILD_VERSION, + ], +) + +load("@build_bazel_rules_nodejs//:index.bzl", "npm_install") + +npm_install( + name = "npm", + package_json = "//:package.json", + package_lock_json = "//:package-lock.json", +) diff --git a/examples/esbuild/package-lock.json b/examples/esbuild/package-lock.json new file mode 100644 index 0000000000..adaa9ece5e --- /dev/null +++ b/examples/esbuild/package-lock.json @@ -0,0 +1,178 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@bazel/typescript": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@bazel/typescript/-/typescript-3.0.0.tgz", + "integrity": "sha512-qYsfyi/+7QOFP9uVAv3gKaqkxo+fIamFrdQ71K85FlJSowxAkwj51pxOPnIWBcMzFVNv1p2ZyfM3ZctKqGye2g==", + "dev": true, + "requires": { + "protobufjs": "6.8.8", + "semver": "5.6.0", + "source-map-support": "0.5.9", + "tsutils": "2.27.2" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", + "dev": true + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", + "dev": true + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dev": true, + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", + "dev": true + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", + "dev": true + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", + "dev": true + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", + "dev": true + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", + "dev": true + }, + "@types/node": { + "version": "12.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.3.tgz", + "integrity": "sha512-7TEYTQT1/6PP53NftXXabIZDaZfaoBdeBm8Md/i7zsWRoBe0YwOXguyK8vhHs8ehgB/w9U4K/6EWuTyp0W6nIA==", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "dev": true + }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "dev": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.51", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.51.tgz", + "integrity": "sha512-KANw+MkL626tq90l++hGelbl67irOJzGhUJk6a1Bt8QHOeh9tztJx+L0AqttraWKinmZn7Qi5lJZJzx45Gq0dg==", + "dev": true + } + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true + }, + "tsutils": { + "version": "2.27.2", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.2.tgz", + "integrity": "sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "dev": true + } + } +} diff --git a/examples/esbuild/package.json b/examples/esbuild/package.json new file mode 100644 index 0000000000..ea8cf786b8 --- /dev/null +++ b/examples/esbuild/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "devDependencies": { + "@bazel/esbuild": "^3.0.0", + "@bazel/typescript": "^3.0.0", + "@types/node": "12.6.3", + "tslib": "1.9.0", + "typescript": "3.5.3" + }, + "scripts": { + "test": "bazel test //..." + } +} diff --git a/examples/esbuild/src/BUILD.bazel b/examples/esbuild/src/BUILD.bazel new file mode 100644 index 0000000000..5100f4eaef --- /dev/null +++ b/examples/esbuild/src/BUILD.bazel @@ -0,0 +1,53 @@ +load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test", "nodejs_binary", "npm_package_bin") +load("@npm//@bazel/esbuild:index.bzl", "esbuild") +load("@npm//@bazel/typescript:index.bzl", "ts_project") + +# build the Typescript to JS with ts_project +ts_project( + name = "lib", + srcs = [ + "main.ts", + "name.ts", + ], + tsconfig = {}, +) + +# create a single bundle of the JS sources +esbuild( + name = "bundle", + entry_point = "main.ts", + minify = True, + # setting node as the platform will default us to CJS + platform = "node", + tool = select({ + "@bazel_tools//src/conditions:darwin": "@esbuild_darwin//:bin/esbuild", + "@bazel_tools//src/conditions:linux_x86_64": "@esbuild_linux//:bin/esbuild", + "@bazel_tools//src/conditions:windows": "@esbuild_windows//:esbuild.exe", + }), + deps = [ + ":lib", + ], +) + +# binary for running our tool +nodejs_binary( + name = "bin", + data = [ + ":bundle", + ], + entry_point = "bundle.js", +) + +# run the built tool, capturing the stdout to the text file +npm_package_bin( + name = "greeter", + stdout = "greeting.txt", + tool = ":bin", +) + +# ensure our text file is what we are expecting +generated_file_test( + name = "test", + src = "greeting.golden.txt", + generated = "greeting.txt", +) diff --git a/examples/esbuild/src/greeting.golden.txt b/examples/esbuild/src/greeting.golden.txt new file mode 100644 index 0000000000..bf712725ad --- /dev/null +++ b/examples/esbuild/src/greeting.golden.txt @@ -0,0 +1 @@ +Hello rules_nodejs! diff --git a/examples/esbuild/src/main.ts b/examples/esbuild/src/main.ts new file mode 100644 index 0000000000..931164fb4d --- /dev/null +++ b/examples/esbuild/src/main.ts @@ -0,0 +1,8 @@ +import {NAME} from './name'; + +export function greeting(name: string): string { + return `Hello ${name}!`; +} + +const sentance = greeting(NAME); +console.log(sentance); diff --git a/examples/esbuild/src/name.ts b/examples/esbuild/src/name.ts new file mode 100644 index 0000000000..c18ea6bac7 --- /dev/null +++ b/examples/esbuild/src/name.ts @@ -0,0 +1 @@ +export const NAME = 'rules_nodejs'; diff --git a/internal/linker/link_node_modules.bzl b/internal/linker/link_node_modules.bzl index 4f8124416a..2c1e056d78 100644 --- a/internal/linker/link_node_modules.bzl +++ b/internal/linker/link_node_modules.bzl @@ -19,7 +19,7 @@ def _debug(vars, *args): print("[link_node_modules.bzl]", *args) # Arbitrary name; must be chosen to globally avoid conflicts with any other aspect -_ASPECT_RESULT_NAME = "link_node_modules__aspect_result" +ASPECT_RESULT_NAME = "link_node_modules__aspect_result" # Traverse 'srcs' in addition so that we can go across a genrule _MODULE_MAPPINGS_DEPS_NAMES = ["data", "deps", "srcs"] @@ -81,7 +81,7 @@ def write_node_modules_manifest(ctx, extra_data = [], mnemonic = None, link_work fail("All npm dependencies need to come from a single workspace. Found '%s' and '%s'." % (node_modules_root, possible_root)) # ...first-party packages to be linked into the node_modules tree - for k, v in getattr(dep, _ASPECT_RESULT_NAME, {}).items(): + for k, v in getattr(dep, ASPECT_RESULT_NAME, {}).items(): if _link_mapping(dep.label, mappings, k, v): # Special case for ts_library module_name for legacy behavior and for AMD name # work-around. Do not propagate tslibrary root type to runtime as it is not @@ -126,7 +126,7 @@ def _get_module_mappings(target, ctx): # Propogate transitive mappings for name in _MODULE_MAPPINGS_DEPS_NAMES: for dep in getattr(ctx.rule.attr, name, []): - for k, v in getattr(dep, _ASPECT_RESULT_NAME, {}).items(): + for k, v in getattr(dep, ASPECT_RESULT_NAME, {}).items(): # A package which was reachable transitively via a *_binary or *_test # rule is assumed to be in the runfiles of that binary, # so we switch the linker target root. @@ -172,9 +172,9 @@ def _get_module_mappings(target, ctx): def _module_mappings_aspect_impl(target, ctx): # Use a dictionary to construct the result struct - # so that we can reference the _ASPECT_RESULT_NAME variable + # so that we can reference the ASPECT_RESULT_NAME variable return struct(**{ - _ASPECT_RESULT_NAME: _get_module_mappings(target, ctx), + ASPECT_RESULT_NAME: _get_module_mappings(target, ctx), }) module_mappings_aspect = aspect( diff --git a/packages/esbuild/BUILD.bazel b/packages/esbuild/BUILD.bazel new file mode 100644 index 0000000000..9c24788b61 --- /dev/null +++ b/packages/esbuild/BUILD.bazel @@ -0,0 +1,85 @@ +# Copyright 2020 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load("@build_bazel_rules_nodejs//:tools/defaults.bzl", "codeowners", "pkg_npm") +load("@build_bazel_rules_nodejs//tools/stardoc:index.bzl", "stardoc") +load("//third_party/github.com/bazelbuild/bazel-skylib:rules/copy_file.bzl", "copy_file") + +package(default_visibility = ["//visibility:public"]) + +codeowners( + teams = ["@mattem"], +) + +bzl_library( + name = "bzl", + srcs = glob(["**/*.bzl"]), + deps = [ + "@bazel_skylib//lib:paths", + "@build_bazel_rules_nodejs//:bzl", + "@build_bazel_rules_nodejs//internal/common:bzl", + "@build_bazel_rules_nodejs//internal/node:bzl", + ], +) + +stardoc( + name = "docs", + testonly = True, + out = "index.md", + input = "index.bzl", + tags = ["fix-windows"], + deps = [":bzl"], +) + +genrule( + name = "generate_README", + srcs = [ + "_README.md", + "index.md", + ], + outs = ["README.md"], + cmd = """cat $(execpath _README.md) $(execpath index.md) | sed 's/^##/\\\n##/' > $@""", + tags = ["fix-windows"], + visibility = ["//docs:__pkg__"], +) + +copy_file( + name = "npm_version_check", + src = "//internal:npm_version_check.js", + out = ":npm_version_check.js", +) + +pkg_npm( + name = "npm_package", + srcs = [ + "esbuild.bzl", + "helpers.bzl", + "index.bzl", + "package.json", + ], + build_file_content = " ", + substitutions = dict({ + "@build_bazel_rules_nodejs//packages/esbuild:esbuild.bzl": "//@bazel/esbuild:esbuild.bzl", + }), + deps = [ + ":npm_version_check", + ] + select({ + # FIXME: fix stardoc on Windows; //packages/karma:index.md generation fails with: + # ERROR: D:/b/62unjjin/external/npm_bazel_karma/BUILD.bazel:65:1: Couldn't build file + # external/npm_bazel_karma/docs.raw: Generating proto for Starlark doc for docs failed (Exit 1) + "@bazel_tools//src/conditions:windows": [], + "//conditions:default": [":generate_README"], + }), +) diff --git a/packages/esbuild/_README.md b/packages/esbuild/_README.md new file mode 100644 index 0000000000..a81427c781 --- /dev/null +++ b/packages/esbuild/_README.md @@ -0,0 +1,120 @@ +# esbuild rules for Bazel + +The esbuild rules runs the [esbuild](https://github.com/evanw/esbuild) bundler tool with Bazel. + +## Installation + +Add the `@bazel/esbuild` npm packages to your `devDependencies` in `package.json`. + +``` +npm install --save-dev @bazel/esbuild +``` +or using yarn +``` +yarn add -D @bazel/esbuild +``` + +Add an `http_archive` fetching the esbuild binary for each platform that you need to support. +If it's not included in your `WORKSPACE` file already, add a reference to `bazel_skylib` too: + +```python +http_archive( + name = "bazel_skylib", + sha256 = "...", + strip_prefix = "...", + urls = [ + ... + ], +) + +_ESBUILD_VERSION = "0.8.34" +http_archive( + name = "esbuild_darwin", + urls = [ + "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-%s.tgz" % _ESBUILD_VERSION, + ], + strip_prefix = "package", + build_file_content = """exports_files(["bin/esbuild"])""", + sha256 = "3bf980b5175df873dd84fd614d57722f3b1b9c7e74929504e26192d23075d5c3", +) + +http_archive( + name = "esbuild_windows", + urls = [ + "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-%s.tgz" % _ESBUILD_VERSION, + ], + strip_prefix = "package", + build_file_content = """exports_files(["esbuild.exe"])""", + sha256 = "826cd58553e7b6910dd22aba001cd72af34e05c9c3e9af567b5b2a6b1c9f3941", +) + +http_archive( + name = "esbuild_linux", + urls = [ + "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-%s.tgz" % _ESBUILD_VERSION, + ], + strip_prefix = "package", + build_file_content = """exports_files(["bin/esbuild"])""", + sha256 = "9dff3f5b06fd964a1cbb6aa9ea5ebf797767f1bd2bac71e084fb0bbefeba24a3", +) +``` + +These can then be referenced on the `tool` attribute of the `esbuild` rule. + +```python +esbuild( + name = "bundle", + ... + tool = select({ + "@bazel_tools//src/conditions:darwin": "@esbuild_darwin//:bin/esbuild", + "@bazel_tools//src/conditions:windows": "@esbuild_windows//:esbuild.exe", + "@bazel_tools//src/conditions:linux_x86_64": "@esbuild_linux//:bin/esbuild", + }), +) +``` + +It might be useful to wrap this locally in a macro for better reuseability, see `packages/esbuild/test/tests.bzl` for an example. + +The `esbuild` rule can take a JS or TS dependency tree and bundle it to a single file, or split across multiple files, outputting a directory. + +```python +load("//packages/esbuild:index.bzl", "esbuild") +load("//packages/typescript:index.bzl", "ts_library") + +ts_library( + name = "lib", + srcs = ["a.ts"], +) + +esbuild( + name = "bundle", + entry_point = "a.ts", + deps = [":lib"], +) +``` + +The above will create three output files, `bundle.js`, `bundle.js.map` and `bundle_metadata.json` which contains the bundle metadata to aid in debugging and resoloution tracing. + +To create a code split bundle, set `splitting = True` on the `esbuild` rule. + +```python +load("//packages/esbuild:index.bzl", "esbuild") +load("//packages/typescript:index.bzl", "ts_library") + +ts_library( + name = "lib", + srcs = ["a.ts"], + deps = [ + "@npm//foo", + ], +) + +esbuild( + name = "bundle", + entry_point = "a.ts", + deps = [":lib"], + splitting = True, +) +``` + +This will create an output directory containing all the code split chunks, along with their sourcemaps files diff --git a/packages/esbuild/esbuild.bzl b/packages/esbuild/esbuild.bzl new file mode 100644 index 0000000000..a6325ea84d --- /dev/null +++ b/packages/esbuild/esbuild.bzl @@ -0,0 +1,220 @@ +""" +esbuild rule +""" + +load("@build_bazel_rules_nodejs//:providers.bzl", "JSEcmaScriptModuleInfo", "JSModuleInfo", "NpmPackageInfo", "node_modules_aspect") +load("@build_bazel_rules_nodejs//internal/linker:link_node_modules.bzl", "ASPECT_RESULT_NAME", "module_mappings_aspect") +load(":helpers.bzl", "filter_files", "generate_path_mapping", "resolve_js_input", "write_jsconfig_file") + +def _esbuild_impl(ctx): + # For each dep, JSEcmaScriptModuleInfo is used if found, then JSModuleInfo and finally + # the DefaultInfo files are used if the former providers are not found. + deps_depsets = [] + + # Path alias mapings are used to create a jsconfig with mappings so that esbuild + # how to resolve custom package or module names + path_alias_mappings = dict() + + for dep in ctx.attr.deps: + if JSEcmaScriptModuleInfo in dep: + deps_depsets.append(dep[JSEcmaScriptModuleInfo].sources) + + if JSModuleInfo in dep: + deps_depsets.append(dep[JSModuleInfo].sources) + elif hasattr(dep, "files"): + deps_depsets.append(dep.files) + + if NpmPackageInfo in dep: + deps_depsets.append(dep[NpmPackageInfo].sources) + + # Collect the path alias mapping to resolve packages correctly + if hasattr(dep, ASPECT_RESULT_NAME): + for key, value in getattr(dep, ASPECT_RESULT_NAME).items(): + path_alias_mappings.update(generate_path_mapping(key, value[1].replace(ctx.bin_dir.path + "/", ""))) + + deps_inputs = depset(transitive = deps_depsets).to_list() + inputs = filter_files(ctx.files.entry_point, [".mjs", ".js"]) + ctx.files.srcs + deps_inputs + + metafile = ctx.actions.declare_file("%s_metadata.json" % ctx.attr.name) + outputs = [metafile] + + entry_point = resolve_js_input(ctx.file.entry_point, inputs) + + args = ctx.actions.args() + + args.add("--bundle", entry_point.path) + args.add("--sourcemap") + args.add("--keep-names") + args.add_joined(["--platform", ctx.attr.platform], join_with = "=") + args.add_joined(["--target", ctx.attr.target], join_with = "=") + args.add_joined(["--log-level", "info"], join_with = "=") + args.add_joined(["--metafile", metafile.path], join_with = "=") + args.add_all(ctx.attr.define, format_each = "--define=%s") + args.add_all(ctx.attr.external, format_each = "--external=%s") + + # disable the error limit and show all errors + args.add_joined(["--error-limit", "0"], join_with = "=") + + if ctx.attr.minify: + args.add("--minify") + else: + # by default, esbuild will tree-shake 'pure' functions + # disable this unless also minifying + args.add_joined(["--tree-shaking", "ignore-annotations"], join_with = "=") + + if ctx.attr.sources_content: + args.add("--sources-content=true") + else: + args.add("--sources-content=false") + + if ctx.attr.splitting: + js_out = ctx.actions.declare_directory("%s" % ctx.attr.name) + outputs.append(js_out) + + args.add("--splitting") + args.add_joined(["--format", "esm"], join_with = "=") + args.add_joined(["--outdir", js_out.path], join_with = "=") + else: + js_out = ctx.outputs.output + js_out_map = ctx.outputs.output_map + outputs.extend([js_out, js_out_map]) + + if ctx.attr.format: + args.add_joined(["--format", ctx.attr.format], join_with = "=") + + args.add_joined(["--outfile", js_out.path], join_with = "=") + + jsconfig_file = write_jsconfig_file(ctx, path_alias_mappings) + args.add_joined(["--tsconfig", jsconfig_file.path], join_with = "=") + inputs.append(jsconfig_file) + + ctx.actions.run( + inputs = inputs, + outputs = outputs, + executable = ctx.executable.tool, + arguments = [args], + progress_message = "%s Javascript %s [esbuild]" % ("Bundling" if not ctx.attr.splitting else "Splitting", entry_point.short_path), + execution_requirements = { + "no-remote-exec": "1", + }, + ) + + return [ + DefaultInfo(files = depset(outputs + [jsconfig_file])), + ] + +esbuild_bundle = rule( + attrs = { + "define": attr.string_list( + default = [], + doc = """A list of global identifier replacements. +Example: +```python +esbuild( + name = "bundle", + define = [ + "process.env.NODE_ENV=\\"production\\"" + ], +) +``` + """, + ), + "deps": attr.label_list( + default = [], + aspects = [module_mappings_aspect, node_modules_aspect], + doc = "A list of direct dependencies that are required to build the bundle", + ), + "entry_point": attr.label( + mandatory = True, + allow_single_file = True, + doc = "The bundle's entry point (e.g. your main.js or app.js or index.js)", + ), + "external": attr.string_list( + default = [], + doc = "A list of module names that are treated as external and not included in the resulting bundle", + ), + "format": attr.string( + values = ["iife", "cjs", "esm", ""], + mandatory = False, + doc = """The output format of the bundle, defaults to iife when platform is browser +and cjs when platform is node. If performing code splitting, defaults to esm""", + ), + "minify": attr.bool( + default = False, + doc = """Minifies the bundle with the built in minification. +Removes whitespace, shortens identifieres and uses equivalent but shorter syntax. + +Sets all --minify-* flags + """, + ), + "output": attr.output( + mandatory = False, + doc = "Name of the output file when bundling", + ), + "output_map": attr.output( + mandatory = False, + doc = "Name of the output source map when bundling", + ), + "platform": attr.string( + default = "browser", + values = ["node", "browser", "neutral", ""], + doc = "The platform to bundle for", + ), + "sources_content": attr.bool( + mandatory = False, + default = False, + doc = "If False, omits the `sourcesContent` field from generated source maps", + ), + "splitting": attr.bool( + default = False, + doc = """If true, esbuild produces an output directory containing all the output files from code splitting + """, + ), + "srcs": attr.label_list( + allow_files = True, + default = [], + doc = """Non-entry point JavaScript source files from the workspace. + +You must not repeat file(s) passed to entry_point""", + ), + "target": attr.string( + default = "es2015", + doc = """Environment target (e.g. es2017, chrome58, firefox57, safari11, +edge16, node10, default esnext) + """, + ), + "tool": attr.label( + allow_single_file = True, + mandatory = True, + executable = True, + cfg = "exec", + doc = "An executable for the esbuild binary", + ), + }, + implementation = _esbuild_impl, +) + +def esbuild(name, splitting = False, **kwargs): + """esbuild helper macro around the `esbuild_bundle` rule + + For a full list of attributes, see the `esbuild_bundle` rule + + Args: + name: The name used for this rule and output files + splitting: If `True`, produce a code split bundle in an output directory + **kwargs: All other args from `esbuild_bundle` + """ + + if splitting == True: + esbuild_bundle( + name = name, + splitting = True, + **kwargs + ) + else: + esbuild_bundle( + name = name, + output = "%s.js" % name, + output_map = "%s.js.map" % name, + **kwargs + ) diff --git a/packages/esbuild/esbuild_repo.bzl b/packages/esbuild/esbuild_repo.bzl new file mode 100644 index 0000000000..d8b740bc86 --- /dev/null +++ b/packages/esbuild/esbuild_repo.bzl @@ -0,0 +1,48 @@ +""" +Helper macro for fetching esbuild versions for internal tests and examples in rules_nodejs +""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +_PLATFORM_SHA = { + "darwin_64": "3bf980b5175df873dd84fd614d57722f3b1b9c7e74929504e26192d23075d5c3", + "linux_64": "9dff3f5b06fd964a1cbb6aa9ea5ebf797767f1bd2bac71e084fb0bbefeba24a3", + "windows_64": "826cd58553e7b6910dd22aba001cd72af34e05c9c3e9af567b5b2a6b1c9f3941", +} + +_VERSION = "0.8.34" + +def esbuild_dependencies(): + """Helper to install required dependencies for the esbuild rules""" + + version = _VERSION + + http_archive( + name = "esbuild_darwin", + urls = [ + "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-%s.tgz" % version, + ], + strip_prefix = "package", + build_file_content = """exports_files(["bin/esbuild"])""", + sha256 = "3bf980b5175df873dd84fd614d57722f3b1b9c7e74929504e26192d23075d5c3", + ) + + http_archive( + name = "esbuild_win", + urls = [ + "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-%s.tgz" % version, + ], + strip_prefix = "package", + build_file_content = """exports_files(["esbuild.exe"])""", + sha256 = "826cd58553e7b6910dd22aba001cd72af34e05c9c3e9af567b5b2a6b1c9f3941", + ) + + http_archive( + name = "esbuild_linux", + urls = [ + "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-%s.tgz" % version, + ], + strip_prefix = "package", + build_file_content = """exports_files(["bin/esbuild"])""", + sha256 = "9dff3f5b06fd964a1cbb6aa9ea5ebf797767f1bd2bac71e084fb0bbefeba24a3", + ) diff --git a/packages/esbuild/helpers.bzl b/packages/esbuild/helpers.bzl new file mode 100644 index 0000000000..11b5a2a9af --- /dev/null +++ b/packages/esbuild/helpers.bzl @@ -0,0 +1,108 @@ +""" +Utility helper functions for the esbuild rule +""" + +load("@bazel_skylib//lib:paths.bzl", "paths") + +def strip_ext(f): + "Strips the extension of a file." + return f.short_path[:-len(f.extension) - 1] + +def resolve_js_input(f, inputs): + """Find a corresponding javascript entrypoint for a provided file + + Args: + f: The file where its basename is used to match the entrypoint + inputs: The list of files where it should take a look at + + Returns: + Returns the file that is the corresponding entrypoint + """ + if f.extension == "js" or f.extension == "mjs": + return f + + no_ext = strip_ext(f) + for i in inputs: + if i.extension == "js" or i.extension == "mjs": + if strip_ext(i) == no_ext: + return i + fail("Could not find corresponding javascript entry point for %s. Add the %s.js to your deps." % (f.path, no_ext)) + +def filter_files(input, endings = [".js"]): + """Filters a list of files for specific endings + + Args: + input: The depset or list of files + endings: The list of endings that should be filtered for + + Returns: + Returns the filtered list of files + """ + + # Convert input into list regardles of being a depset or list + input_list = input.to_list() if type(input) == "depset" else input + filtered = [] + + for file in input_list: + for ending in endings: + if file.path.endswith(ending): + filtered.append(file) + continue + + return filtered + +def generate_path_mapping(package_name, path): + """Generate a path alias mapping for a jsconfig.json + + For example: {"@my-alias/*": [ "path/to/my-alias/*" ]}, + + Args: + package_name: The module name + path: The base path of the package + """ + + pkg = {} + + # entry for the barrel files favor mjs over normal as it results + # in smaller bundles + pkg[package_name] = [ + path + "/index.mjs", + path, + ] + + # A glob import for deep package imports + pkg[package_name + "/*"] = [path + "/*"] + + return pkg + +def write_jsconfig_file(ctx, path_alias_mappings): + """Writes the js config file for the path alias mappings. + + Args: + ctx: The rule context + path_alias_mappings: Dict with the mappings + + """ + + # The package path + rule_path = paths.dirname(ctx.build_file_path) + + # Replace all segments in the path with .. join them with "/" and postfix + # it with another / to get a relative path from the build file dir + # to the workspace root. + base_url_path = "/".join([".." for segment in rule_path.split("/")]) + "/" + + # declare the jsconfig_file + jsconfig_file = ctx.actions.declare_file("%s.config.json" % ctx.attr.name) + + # write the config file + ctx.actions.write( + output = jsconfig_file, + content = struct(compilerOptions = struct( + rootDirs = ["."], + baseUrl = base_url_path, + paths = path_alias_mappings, + )).to_json(), + ) + + return jsconfig_file diff --git a/packages/esbuild/index.bzl b/packages/esbuild/index.bzl new file mode 100644 index 0000000000..6fc62d0791 --- /dev/null +++ b/packages/esbuild/index.bzl @@ -0,0 +1,28 @@ +# Copyright 2020 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Public API surface is re-exported here. +""" + +load( + "@build_bazel_rules_nodejs//packages/esbuild:esbuild.bzl", + _esbuild = "esbuild", + _esbuild_bundle = "esbuild_bundle", +) + +esbuild = _esbuild +esbuild_bundle = _esbuild_bundle + +# DO NOT ADD MORE rules here unless they appear in the generated docsite. +# Run yarn stardoc to re-generate the docsite. diff --git a/packages/esbuild/package.json b/packages/esbuild/package.json new file mode 100644 index 0000000000..23ba1748b0 --- /dev/null +++ b/packages/esbuild/package.json @@ -0,0 +1,17 @@ +{ + "name": "@bazel/esbuild", + "description": "esbuild rules for Bazel", + "license": "Apache-2.0", + "version": "0.0.0-PLACEHOLDER", + "repository": { + "type": "git", + "url": "https://github.com/bazelbuild/rules_nodejs.git", + "directory": "packages/esbuild" + }, + "bugs": { + "url": "https://github.com/bazelbuild/rules_nodejs/issues" + }, + "keywords": [ + "bazel" + ] +} diff --git a/packages/esbuild/test/BUILD.bazel b/packages/esbuild/test/BUILD.bazel new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/esbuild/test/alias-mapping/BUILD.bazel b/packages/esbuild/test/alias-mapping/BUILD.bazel new file mode 100644 index 0000000000..2e6d1f0e46 --- /dev/null +++ b/packages/esbuild/test/alias-mapping/BUILD.bazel @@ -0,0 +1,29 @@ +load("//:index.bzl", "generated_file_test") +load("//packages/esbuild/test:tests.bzl", "esbuild") + +esbuild( + name = "bundle", + entry_point = "main.js", + format = "esm", + deps = [ + "//packages/esbuild/test/alias-mapping/module-one", + "//packages/esbuild/test/alias-mapping/module-two", + ], +) + +# esbuild will put the filepath in a comment within the non-minified file, +# on different platforms this will cause the golden test to differ +# strip them here +# note that this regex doesn't strip the sourcemap URI comment +genrule( + name = "strip_bundle_comments", + srcs = ["bundle.js"], + outs = ["bundle.stripped.js"], + cmd = "cat $(location :bundle.js) | sed \"s#// .*##\" > $@", +) + +generated_file_test( + name = "bundle_test", + src = "bundle.golden.txt", + generated = "bundle.stripped.js", +) diff --git a/packages/esbuild/test/alias-mapping/bundle.golden.txt b/packages/esbuild/test/alias-mapping/bundle.golden.txt new file mode 100644 index 0000000000..19ed8a39ab --- /dev/null +++ b/packages/esbuild/test/alias-mapping/bundle.golden.txt @@ -0,0 +1,15 @@ +var __defProp = Object.defineProperty; +var __name = (target, value) => __defProp(target, "name", {value, configurable: true}); + + +var getId = /* @__PURE__ */ __name(() => "module-one", "getId"); + + +var getId2 = /* @__PURE__ */ __name(() => "module-two", "getId"); + + +var main_default = `Full ID: ${getId} - ${getId2}`; +export { + main_default as default +}; +//# sourceMappingURL=bundle.js.map diff --git a/packages/esbuild/test/alias-mapping/main.js b/packages/esbuild/test/alias-mapping/main.js new file mode 100644 index 0000000000..21a284e732 --- /dev/null +++ b/packages/esbuild/test/alias-mapping/main.js @@ -0,0 +1,4 @@ +import {getId as m1Id} from '@alias-mapping/module-one'; +import {getId as m2Id} from '@alias-mapping/module-two'; + +export default `Full ID: ${m1Id} - ${m2Id}`; diff --git a/packages/esbuild/test/alias-mapping/module-one/BUILD.bazel b/packages/esbuild/test/alias-mapping/module-one/BUILD.bazel new file mode 100644 index 0000000000..1ecff9c034 --- /dev/null +++ b/packages/esbuild/test/alias-mapping/module-one/BUILD.bazel @@ -0,0 +1,9 @@ +load("//internal/js_library:js_library.bzl", "js_library") + +package(default_visibility = ["//packages/esbuild/test:__subpackages__"]) + +js_library( + name = "module-one", + package_name = "@alias-mapping/module-one", + srcs = [":index.js"], +) diff --git a/packages/esbuild/test/alias-mapping/module-one/index.js b/packages/esbuild/test/alias-mapping/module-one/index.js new file mode 100644 index 0000000000..be8c740ce1 --- /dev/null +++ b/packages/esbuild/test/alias-mapping/module-one/index.js @@ -0,0 +1 @@ +export const getId = () => 'module-one'; diff --git a/packages/esbuild/test/alias-mapping/module-two/BUILD.bazel b/packages/esbuild/test/alias-mapping/module-two/BUILD.bazel new file mode 100644 index 0000000000..6927d4ccf8 --- /dev/null +++ b/packages/esbuild/test/alias-mapping/module-two/BUILD.bazel @@ -0,0 +1,9 @@ +load("//internal/js_library:js_library.bzl", "js_library") + +package(default_visibility = ["//packages/esbuild/test:__subpackages__"]) + +js_library( + name = "module-two", + package_name = "@alias-mapping/module-two", + srcs = [":index.js"], +) diff --git a/packages/esbuild/test/alias-mapping/module-two/index.js b/packages/esbuild/test/alias-mapping/module-two/index.js new file mode 100644 index 0000000000..4fa928033d --- /dev/null +++ b/packages/esbuild/test/alias-mapping/module-two/index.js @@ -0,0 +1 @@ +export const getId = () => 'module-two'; diff --git a/packages/esbuild/test/bundle/BUILD.bazel b/packages/esbuild/test/bundle/BUILD.bazel new file mode 100644 index 0000000000..b8e68bcbea --- /dev/null +++ b/packages/esbuild/test/bundle/BUILD.bazel @@ -0,0 +1,58 @@ +load("//:index.bzl", "generated_file_test") +load("//packages/esbuild/test:tests.bzl", "esbuild") +load("//packages/typescript:index.bzl", "ts_library") + +ts_library( + name = "index", + srcs = ["index.ts"], + module_name = "lib", +) + +ts_library( + name = "lib", + srcs = ["a.ts"], + deps = [":index"], +) + +esbuild( + name = "bundle", + entry_point = "a.ts", + deps = [":lib"], +) + +esbuild( + name = "bundle.min", + entry_point = "a.ts", + minify = True, + deps = [":lib"], +) + +esbuild( + name = "bundle.split", + entry_point = "a.ts", + splitting = True, + deps = [":lib"], +) + +# esbuild will put the filepath in a comment within the non-minified file, +# on different platforms this will cause the golden test to differ +# strip the platform agnostic part of it +# note that this regex doesn't strip the sourcemap URI comment +genrule( + name = "strip_bundle_comments", + srcs = ["bundle.js"], + outs = ["bundle.stripped.js"], + cmd = "cat $(location :bundle.js) | sed \"s#// .*##\" > $@", +) + +generated_file_test( + name = "bundle_test", + src = "bundle.golden.txt", + generated = "bundle.stripped.js", +) + +generated_file_test( + name = "bundle_min_test", + src = "bundle.min.golden.txt", + generated = "bundle.min.js", +) diff --git a/packages/esbuild/test/bundle/a.ts b/packages/esbuild/test/bundle/a.ts new file mode 100644 index 0000000000..4979aafe0b --- /dev/null +++ b/packages/esbuild/test/bundle/a.ts @@ -0,0 +1,3 @@ +import {NAME} from 'lib'; + +console.log(`Hello ${NAME}`); \ No newline at end of file diff --git a/packages/esbuild/test/bundle/bundle.golden.txt b/packages/esbuild/test/bundle/bundle.golden.txt new file mode 100644 index 0000000000..5583922b8b --- /dev/null +++ b/packages/esbuild/test/bundle/bundle.golden.txt @@ -0,0 +1,8 @@ +(() => { + + var NAME = "bazel"; + + + console.log(`Hello ${NAME}`); +})(); +//# sourceMappingURL=bundle.js.map diff --git a/packages/esbuild/test/bundle/bundle.min.golden.txt b/packages/esbuild/test/bundle/bundle.min.golden.txt new file mode 100644 index 0000000000..37e8681982 --- /dev/null +++ b/packages/esbuild/test/bundle/bundle.min.golden.txt @@ -0,0 +1,2 @@ +(()=>{var o="bazel";console.log(`Hello ${o}`);})(); +//# sourceMappingURL=bundle.min.js.map diff --git a/packages/esbuild/test/bundle/index.ts b/packages/esbuild/test/bundle/index.ts new file mode 100644 index 0000000000..6d6d9837ea --- /dev/null +++ b/packages/esbuild/test/bundle/index.ts @@ -0,0 +1 @@ +export const NAME = 'bazel'; diff --git a/packages/esbuild/test/splitting/BUILD.bazel b/packages/esbuild/test/splitting/BUILD.bazel new file mode 100644 index 0000000000..d5cbc9b2e8 --- /dev/null +++ b/packages/esbuild/test/splitting/BUILD.bazel @@ -0,0 +1,36 @@ +load("//:index.bzl", "nodejs_test") +load("//:tools/defaults.bzl", "pkg_tar") +load("//packages/esbuild/test:tests.bzl", "esbuild") +load("//packages/typescript:index.bzl", "ts_library") + +ts_library( + name = "main", + srcs = [ + "main.ts", + "other.ts", + ], + deps = [ + "@npm//@angular/core", + ], +) + +esbuild( + name = "bundle", + entry_point = "main.ts", + splitting = True, + deps = [":main"], +) + +pkg_tar( + name = "tar", + srcs = [":bundle"], +) + +nodejs_test( + name = "bundle_test", + data = [ + "bundle.spec.js", + ":bundle", + ], + entry_point = ":bundle.spec.js", +) diff --git a/packages/esbuild/test/splitting/bundle.spec.js b/packages/esbuild/test/splitting/bundle.spec.js new file mode 100644 index 0000000000..fe78b0957a --- /dev/null +++ b/packages/esbuild/test/splitting/bundle.spec.js @@ -0,0 +1,17 @@ +const {join} = require('path'); +const {readFileSync, lstatSync} = require('fs'); + +const helper = require(process.env.BAZEL_NODE_RUNFILES_HELPER); +const location = helper.resolve('build_bazel_rules_nodejs/packages/esbuild/test/splitting/bundle'); + +const main = readFileSync(join(location, 'main.js'), {encoding: 'utf8'}); +const hasImportOfCore = main.indexOf(`import("./other.js")`) > -1; + +if (!hasImportOfCore) { + console.error(`Expected entry_point 'main.js' to have an import of './other.js'`); +} + +// throws if file does not exist +lstatSync(join(location, 'other.js')); + +process.exit(hasImportOfCore ? 0 : 1); diff --git a/packages/esbuild/test/splitting/main.ts b/packages/esbuild/test/splitting/main.ts new file mode 100644 index 0000000000..b4810f3fda --- /dev/null +++ b/packages/esbuild/test/splitting/main.ts @@ -0,0 +1 @@ +import('./other').then(module => {console.log(module.OTHER);}); diff --git a/packages/esbuild/test/splitting/other.ts b/packages/esbuild/test/splitting/other.ts new file mode 100644 index 0000000000..9485b32b53 --- /dev/null +++ b/packages/esbuild/test/splitting/other.ts @@ -0,0 +1 @@ +export const OTHER = true; diff --git a/packages/esbuild/test/tests.bzl b/packages/esbuild/test/tests.bzl new file mode 100644 index 0000000000..aed4aed16d --- /dev/null +++ b/packages/esbuild/test/tests.bzl @@ -0,0 +1,13 @@ +"""Default esbuild binary selection for tests""" + +load("//packages/esbuild:index.bzl", _esbuild = "esbuild") + +def esbuild(**kwargs): + _esbuild( + tool = select({ + "@bazel_tools//src/conditions:darwin": "@esbuild_darwin//:bin/esbuild", + "@bazel_tools//src/conditions:linux_x86_64": "@esbuild_linux//:bin/esbuild", + "@bazel_tools//src/conditions:windows": "@esbuild_windows//:esbuild.exe", + }), + **kwargs + ) diff --git a/packages/esbuild/test/typescript/BUILD.bazel b/packages/esbuild/test/typescript/BUILD.bazel new file mode 100644 index 0000000000..b48a33f09f --- /dev/null +++ b/packages/esbuild/test/typescript/BUILD.bazel @@ -0,0 +1,36 @@ +load("//:index.bzl", "generated_file_test") +load("//packages/esbuild/test:tests.bzl", "esbuild") +load("//packages/typescript:index.bzl", "ts_library") + +exports_files(["tsconfig.json"]) + +ts_library( + name = "main", + srcs = [":main.ts"], + tsconfig = ":tsconfig.json", + deps = [ + "//packages/esbuild/test/typescript/module-dynamic", + "//packages/esbuild/test/typescript/module-one", + "//packages/esbuild/test/typescript/module-two", + ], +) + +esbuild( + name = "bundle", + entry_point = "main.ts", + format = "esm", + deps = [":main"], +) + +genrule( + name = "strip_bundle_comments", + srcs = ["bundle.js"], + outs = ["bundle.stripped.js"], + cmd = "cat $(location :bundle.js) | sed \"s#// .*##\" > $@", +) + +generated_file_test( + name = "bundle_test", + src = "bundle.golden.txt", + generated = ":bundle.stripped.js", +) diff --git a/packages/esbuild/test/typescript/bundle.golden.txt b/packages/esbuild/test/typescript/bundle.golden.txt new file mode 100644 index 0000000000..80f6bfdc08 --- /dev/null +++ b/packages/esbuild/test/typescript/bundle.golden.txt @@ -0,0 +1,62 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __markAsModule = (target) => __defProp(target, "__esModule", {value: true}); +var __name = (target, value) => __defProp(target, "name", {value, configurable: true}); +var __commonJS = (callback, module) => () => { + if (!module) { + module = {exports: {}}; + callback(module.exports, module); + } + return module.exports; +}; +var __exportStar = (target, module, desc) => { + __markAsModule(target); + if (module && typeof module === "object" || typeof module === "function") { + for (let key of __getOwnPropNames(module)) + if (!__hasOwnProp.call(target, key) && key !== "default") + __defProp(target, key, {get: () => module[key], enumerable: !(desc = __getOwnPropDesc(module, key)) || desc.enumerable}); + } + return target; +}; +var __toModule = (module) => { + if (module && module.__esModule) + return module; + return __exportStar(__defProp(module != null ? __create(__getProtoOf(module)) : {}, "default", {value: module, enumerable: true}), module); +}; + + +var require_module_dynamic = __commonJS((exports, module) => { + (function(factory) { + if (typeof module === "object" && typeof module.exports === "object") { + var v = factory(require, exports); + if (v !== void 0) + module.exports = v; + } else if (typeof define === "function" && define.amd) { + define("build_bazel_rules_nodejs/packages/esbuild/test/typescript/module-dynamic/index", ["require", "exports"], factory); + } + })(function(require2, exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", {value: true}); + exports2.getId = () => "dynamic-id"; + }); +}); + + +var import_module_dynamic = __toModule(require_module_dynamic()); + + +var getId = /* @__PURE__ */ __name(() => "module-one", "getId"); + + +var getId2 = /* @__PURE__ */ __name(() => "module-two", "getId"); + + +var main_default = `Full ID: ${getId} - ${getId2} - ${import_module_dynamic.getId}`; +export { + main_default as default +}; +//# sourceMappingURL=bundle.js.map diff --git a/packages/esbuild/test/typescript/main.ts b/packages/esbuild/test/typescript/main.ts new file mode 100644 index 0000000000..e2359f95d6 --- /dev/null +++ b/packages/esbuild/test/typescript/main.ts @@ -0,0 +1,5 @@ +import {getId as mdyn} from '@typescript/module-dynamic'; +import {getId as m1Id} from '@typescript/module-one'; +import {getId as m2Id} from '@typescript/module-two'; + +export default `Full ID: ${m1Id} - ${m2Id} - ${mdyn}`; diff --git a/packages/esbuild/test/typescript/module-dynamic/BUILD.bazel b/packages/esbuild/test/typescript/module-dynamic/BUILD.bazel new file mode 100644 index 0000000000..8f75f0a555 --- /dev/null +++ b/packages/esbuild/test/typescript/module-dynamic/BUILD.bazel @@ -0,0 +1,17 @@ +load("//internal/js_library:js_library.bzl", "js_library") +load("//packages/typescript:index.bzl", "ts_library") + +package(default_visibility = ["//packages/esbuild/test:__subpackages__"]) + +ts_library( + name = "compile", + srcs = [":index.ts"], + tsconfig = "//packages/esbuild/test/typescript:tsconfig.json", +) + +js_library( + name = "module-dynamic", + package_name = "@typescript/module-dynamic", + srcs = [":random-file.css"], + deps = [":compile"], +) diff --git a/packages/esbuild/test/typescript/module-dynamic/index.ts b/packages/esbuild/test/typescript/module-dynamic/index.ts new file mode 100644 index 0000000000..b6fec9e81b --- /dev/null +++ b/packages/esbuild/test/typescript/module-dynamic/index.ts @@ -0,0 +1 @@ +export const getId = () => 'dynamic-id'; diff --git a/packages/esbuild/test/typescript/module-dynamic/random-file.css b/packages/esbuild/test/typescript/module-dynamic/random-file.css new file mode 100644 index 0000000000..da0e4c781b --- /dev/null +++ b/packages/esbuild/test/typescript/module-dynamic/random-file.css @@ -0,0 +1,3 @@ +.some-random { + font-family: 'Comic Sans'; +} diff --git a/packages/esbuild/test/typescript/module-one/BUILD.bazel b/packages/esbuild/test/typescript/module-one/BUILD.bazel new file mode 100644 index 0000000000..de33f9b0f4 --- /dev/null +++ b/packages/esbuild/test/typescript/module-one/BUILD.bazel @@ -0,0 +1,10 @@ +load("//packages/typescript:index.bzl", "ts_library") + +package(default_visibility = ["//packages/esbuild/test:__subpackages__"]) + +ts_library( + name = "module-one", + srcs = [":index.ts"], + module_name = "@typescript/module-one", + tsconfig = "//packages/esbuild/test/typescript:tsconfig.json", +) diff --git a/packages/esbuild/test/typescript/module-one/index.ts b/packages/esbuild/test/typescript/module-one/index.ts new file mode 100644 index 0000000000..be8c740ce1 --- /dev/null +++ b/packages/esbuild/test/typescript/module-one/index.ts @@ -0,0 +1 @@ +export const getId = () => 'module-one'; diff --git a/packages/esbuild/test/typescript/module-two/BUILD.bazel b/packages/esbuild/test/typescript/module-two/BUILD.bazel new file mode 100644 index 0000000000..14f755f4f0 --- /dev/null +++ b/packages/esbuild/test/typescript/module-two/BUILD.bazel @@ -0,0 +1,10 @@ +load("//packages/typescript:index.bzl", "ts_library") + +package(default_visibility = ["//packages/esbuild/test:__subpackages__"]) + +ts_library( + name = "module-two", + srcs = [":index.ts"], + module_name = "@typescript/module-two", + tsconfig = "//packages/esbuild/test/typescript:tsconfig.json", +) diff --git a/packages/esbuild/test/typescript/module-two/index.ts b/packages/esbuild/test/typescript/module-two/index.ts new file mode 100644 index 0000000000..4fa928033d --- /dev/null +++ b/packages/esbuild/test/typescript/module-two/index.ts @@ -0,0 +1 @@ +export const getId = () => 'module-two'; diff --git a/packages/esbuild/test/typescript/tsconfig.json b/packages/esbuild/test/typescript/tsconfig.json new file mode 100644 index 0000000000..fb77ef436f --- /dev/null +++ b/packages/esbuild/test/typescript/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "esModuleInterop": true, + "skipLibCheck": true + } +}