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

Shift plexus to TypeScript (from flowtypes) #331

Merged
merged 14 commits into from
Mar 8, 2019
Merged
111 changes: 111 additions & 0 deletions BUILD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Build Considerations: Project Root

`yarn` is used instead of `npm`.

## `package.json`

### Dependencies (dev and otherwise)

#### `@typescript-eslint/eslint-plugin`

ESLint is being used to lint the repo, as a whole. Within `./packages/plexus` (for now), [`@typescript-eslint/eslint-plugin`](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin) is used to apply ESLint to TypeScript. This application is localized to plexus via configuring `./packages/plexus/.eslintrc.js` for TypeScript, which means the change in settings is only applied to subdirectories of `./packages/plexus`. This package works really well, but there are quite a few issues it doesn't catch. For that, we use the TypeScript compiler.

#### `typescript`

The TypeScript package (e.g. `typescript`) is **not for compiling** TypeScript source but is included for the purpose of bolstering the linting of TypeScript files. `tsc` catches quite a few issues that ESLint does not pick up on.

### Workspaces

[Create React App](https://facebook.github.io/create-react-app/) (CRA) is used as the build-tooling for the Jaeger UI website. In 2.1.2+ CRA introduced a guard for the `start`, `build` and `test` scripts which checks the version of NPM packages available to make sure they're consistent with CRA's expectations ([reference](https://github.com/facebook/create-react-app/blob/dea19fdb30c2e896ed8ac75b68a612b0b92b2406/packages/react-scripts/scripts/utils/verifyPackageTree.js#L23-L29)). This process checks `node_modules` in parent directors and errors if an unexpected package version is encountered.
tiffon marked this conversation as resolved.
Show resolved Hide resolved

To avoid a world of pain, the [`nohoist`](https://yarnpkg.com/blog/2018/02/15/nohoist/#scope-private) feature of `yarn` workspaces is leveraged. CRA and it's dependencies are local to `./packages/jaeger-ui/node_modules` instead of `./node_modules`, i.e. they're not hoisted. This ensures CRA is using the packages it expects to use.

Unfortunately, the CRA check is not savvy to `yarn` workspaces and errors even though the _`yarn` workspace-magic_ ensures the right packages are actually used by the CRA scripts. So, the escape hatch provided by CRA is used to skip the check: the envvar `SKIP_PREFLIGHT_CHECK=true`, set in `./packages/jaeger-ui/.env`.

### Scripts

#### `build`

`lerna run build` executes the build in each of `./packages/*` sub-packages.

#### `eslint`

This applies ESLint to the repo, as a whole. The TypeScript linting has a distinct configuration, which is a descendent of `./.eslintrc.js`. See **TODO(joe)** TypeScript, above.
tiffon marked this conversation as resolved.
Show resolved Hide resolved

#### `lint`

This is an amalgamation of linting scripts that run to make sure things are all-good. It's run in CI (travis) and as part of a pre-commit hook.

* `prettier-lint`
* `tsc-lint`
* `eslint`
* `flow`
* `check-license`

#### `prepare`

Runs after the top-level `yarn install`. This ensures `./packages/plexus` builds and is available to `./packages/jaeger-ui`.

#### `prettier-comment`, `prettier`, `prettier-lint`

`prettier-comment` is just an explanation for why the `./node_module/.bin/bin-prettier.js` path is used instead of just `yarn prettier etc`; it's due to an [issue with `yarn`](https://github.com/yarnpkg/yarn/issues/6300).

`prettier` formats the code.

`prettier-lint` runs `bin-prettier` in the `--list-different` mode, which only outputs filenames if they would be changed by prettier formatting. If any such files are encountered, the program exits with a non-zero code. This is handy for blocking CI and pre-commits.

#### `tsc-lint`, `tsc-lint-debug`

`tsc` is run with the [`--noEmit`](https://www.typescriptlang.org/docs/handbook/compiler-options.html) option to bolster linting of TypeScript files. See **TODO(joe)** TypeScript, above.
tiffon marked this conversation as resolved.
Show resolved Hide resolved

`tsc-lint-debug` is for diagnosing problems with linking, resolving files, or aliases in TypeScript code. It lists the files involved in the compilation.

### `husky` . `hooks` . `pre-commit`

Runs the `lint` and `test` scripts.

## `.eslintrc.js`

Pretty basic. Needs to be cleaned up. The `airbnb` configuration needs to be updated.
tiffon marked this conversation as resolved.
Show resolved Hide resolved

Note: This configuration is extended by `./packages/plexus/.eslintrc.js`.

## `.flowconfig`

Being phased out.

## `.travis.yml`

Currently `./packages/plexus` doesn't have any tests... But, when it does, `.travis.yml` needs to be updated to send coverage info for all `./packages/*` to codecov.io.
tiffon marked this conversation as resolved.
Show resolved Hide resolved

[`yarn install --frozen-lockfile`](https://yarnpkg.com/lang/en/docs/cli/install/#toc-yarn-install-frozen-lockfile) ensures installs in CI fail if they would typically mutate the lockfile.

## `lerna.json`

We should probably audit our use of `lerna` to make sure a) it's necessary and b) it's idiomatic if it is necessary. We have ended up relying quite a bit on `yarn` workspaces, which has reduced the relevance of `lerna`.
tiffon marked this conversation as resolved.
Show resolved Hide resolved

## `tsconfig.json`

Used to configure the `tsc-lint` script and, in theory, the IDE (such as VS Code).

A few notable [compiler settings](http://www.typescriptlang.org/docs/handbook/compiler-options.html):

* `lib`
* [es2017](https://github.com/Microsoft/TypeScript/blob/master/lib/lib.es2017.d.ts)
* [dom](https://github.com/Microsoft/TypeScript/blob/master/lib/lib.dom.d.ts)
* [dom.iterable](https://github.com/Microsoft/TypeScript/blob/master/lib/lib.dom.iterable.d.ts)
* [webworker](https://github.com/Microsoft/TypeScript/blob/master/lib/lib.webworker.d.ts)
* `skipLibCheck` - Maybe worth reevaluating in the future
* `strict` - Very important
* `noEmit` - We're using this for linting, after all
* `include` - We've included `./typgings` here because it turned out to be a lot simpler than configuring `types`, `typeRoots` and `paths`

## `typings/{custom.d.ts, index.d.ts}`

This is relevant for `./packages/plexus/src/LayoutManager/layout.worker.js` and the `viz.js` package.

I wasn't able to get much in the line of error messaging, so I'm pretty vague on this.

The version of `viz.js` in use (1.8.1) ships with an `index.d.ts` file, but it has some issues. I was able to define alternate type declarations for `viz.js` in `./typings/custom.d.ts` and referring `./typings/index.d.ts` to `./typings/custom.d.ts`. I also changed the import for `viz.js` to `viz.js/viz.js`, which is importing it's main file, directly, instead of implicitly.

For `./packages/plexus/src/LayoutManager/layout.worker.js`, webpack (in `./packages/plexus`) is set up to use the [`worker-loader`](https://github.com/webpack-contrib/worker-loader) to load the file. This converts it to a `WebWorker` by instantiating the `WebWorker` with the source as a `Blob`. Consequently, `layout.worker.js` is implemented in the context of a `WorkerGlobalScope` but consumed as if it's a regular class that extends `Worker`. To deal with this mismatch, a **webpack alias** was created mapping `worker-alias/` to `./packages/plexus/src`. This allowed a type declaration to be defined for `worker-alias/*` as a subclass of `Worker`.
2 changes: 1 addition & 1 deletion packages/plexus/.neutrinorc.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,5 @@ module.exports = neutrino => {
// treated as external modules, so using "worker" as an alias for
// <package_root>/src allows TS to see local workers as a file in an external
// package.
neutrino.config.resolve.alias.set('worker', join(__dirname, 'src'));
neutrino.config.resolve.alias.set('worker-alias', join(__dirname, 'src'));
};
55 changes: 55 additions & 0 deletions packages/plexus/BUILD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Build Considerations: `./packages/plexus`

The package is implemented in TypeScript and must be compiled to JavaScript. The build output goes into `./build` as one main file, `./build/index.js`.

**Note:** File references are relative to `./packages/plexus`. E.g. `./` is actually referring to `./packages/plexus`, relative to the project root.

## Neutrino

[Neutrino](https://master.neutrinojs.org/) is used to build `plexus`. The [release candidate for `v9`](https://github.com/neutrinojs/neutrino/milestone/6) is used.

While Neutrino intends to allow for "zero initial configuration", that turned out not to be the case for `plexus`.

`.neutrinorc.js` has a fair bit of configuration. It's well commented, so it won't be rehashed, here.

### `webpack.config.js`

**Configures the webpack entry point.** Neutrino is used to generate the webpack config, but there were challenges in using it to set a non-Neutrino default entry point.

### `worker-alias`

`worker-alias` is set up as a webpack alias in `.neutrinorc.js`. This alias matches a declaration in the project root: `../../typings/custom.d.ts`. See `../../BUILD.md` for details.

## `package.json`

### Script `prepublishOnly`

Executed after `yarn install` is run in the project root.

### Dependencies (dev and otherwise)

#### `viz.js@1.8.1`

This specific version of [viz.js](https://github.com/mdaines/viz.js) is used to avoid a regression. Meanwhile, [looks like `2.x.x`](https://github.com/mdaines/viz.js/issues/120#issuecomment-389281407) has recovered a lot of ground.
tiffon marked this conversation as resolved.
Show resolved Hide resolved

#### `worker-loader`

[`worker-loader`](https://github.com/webpack-contrib/worker-loader) is a webpack plugin that allows a file to be imported as a class which, when instantiated, creates a WebWorker from the underlying source.

#### `@babel/preset-typescript`

TypeScript is compiled through Babel via [`@babel/preset-typescript`](https://babeljs.io/docs/en/babel-preset-typescript). **The TypeScript compiler is not used to compile TS files.** Note: `tsc` is used to compliment the use of ESLint to lint TypeScript, though.

#### `jest@23.6.0`

Jest is not actually be used, yet. Present as a placeholder.

## `.eslintrc.js`

Configures ESLint for TypeScript. ESLint is executed from the project root, but this file is merged with the project root `.eslintrc.js` and overrides where there is overlap.

Uses [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser) as the parser.

It's worth noting that the `tsconfig.json` is in the project root and `tsconfigRootDir: '.'` refers to the project root.

`prettier/@typescript-eslint` needs to be last in the `extends` so it overrides the formatting rules from `plugin:@typescript-eslint/recommended`.
26 changes: 0 additions & 26 deletions packages/plexus/demo/index.tsx

This file was deleted.

112 changes: 112 additions & 0 deletions packages/plexus/demo/src/data-dag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// 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.

const paths = `
packages
packages/jaeger-ui
packages/jaeger-ui/build
packages/jaeger-ui/build/static
packages/jaeger-ui/build/static/css
packages/jaeger-ui/build/static/js
packages/jaeger-ui/build/static/media
packages/jaeger-ui/node_modules
packages/jaeger-ui/node_modules/.bin
packages/jaeger-ui/node_modules/bluebird
packages/jaeger-ui/node_modules/bluebird/js
packages/jaeger-ui/node_modules/bluebird/js/browser
packages/jaeger-ui/node_modules/bluebird/js/release
packages/jaeger-ui/node_modules/moment
packages/jaeger-ui/node_modules/moment/locale
packages/jaeger-ui/node_modules/moment/min
packages/jaeger-ui/node_modules/moment/src
packages/jaeger-ui/node_modules/moment/src/lib
packages/jaeger-ui/node_modules/moment/src/lib/create
packages/jaeger-ui/node_modules/moment/src/lib/duration
packages/jaeger-ui/node_modules/moment/src/lib/format
packages/jaeger-ui/node_modules/moment/src/lib/locale
packages/jaeger-ui/node_modules/moment/src/lib/moment
packages/jaeger-ui/node_modules/moment/src/lib/parse
packages/jaeger-ui/node_modules/moment/src/lib/units
packages/jaeger-ui/node_modules/moment/src/lib/utils
packages/jaeger-ui/node_modules/moment/src/locale
packages/jaeger-ui/public
packages/jaeger-ui/src
packages/jaeger-ui/src/actions
packages/jaeger-ui/src/api
packages/jaeger-ui/src/components
packages/jaeger-ui/src/components/App
packages/jaeger-ui/src/components/DependencyGraph
packages/jaeger-ui/src/components/SearchTracePage
packages/jaeger-ui/src/components/SearchTracePage/SearchResults
packages/jaeger-ui/src/components/TracePage
packages/jaeger-ui/src/components/TracePage/ArchiveNotifier
packages/jaeger-ui/src/components/TracePage/SpanGraph
packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer
packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ListView
packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/ListView/__snapshots__
packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail
packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/TimelineHeaderRow
packages/jaeger-ui/src/components/common
packages/jaeger-ui/src/constants
packages/jaeger-ui/src/demo
packages/jaeger-ui/src/img
packages/jaeger-ui/src/middlewares
packages/jaeger-ui/src/model
packages/jaeger-ui/src/propTypes
packages/jaeger-ui/src/reducers
packages/jaeger-ui/src/selectors
packages/jaeger-ui/src/types
packages/jaeger-ui/src/utils
packages/jaeger-ui/src/utils/DraggableManager
packages/jaeger-ui/src/utils/DraggableManager/demo
packages/jaeger-ui/src/utils/config
packages/jaeger-ui/src/utils/test
packages/jaeger-ui/src/utils/tracking
packages/plexus
packages/plexus/demo
packages/plexus/demo/dist
packages/plexus/demo/src
packages/plexus/lib
packages/plexus/lib/DirectedGraph
packages/plexus/lib/DirectedGraph/builtins
packages/plexus/lib/LayoutManager
packages/plexus/lib/LayoutManager/dot
packages/plexus/lib/types
packages/plexus/node_modules
packages/plexus/node_modules/.bin
packages/plexus/node_modules/.cache
packages/plexus/node_modules/.cache/babel-loader
packages/plexus/src
packages/plexus/src/DirectedGraph
packages/plexus/src/DirectedGraph/builtins
packages/plexus/src/LayoutManager
packages/plexus/src/LayoutManager/dot
packages/plexus/src/types
packages/plexus/umd
packages/plexus/umd/@jaegertracing
`;

export const vertices = [];
export const edges = [];

paths
.trim()
.split('\n')
.forEach(line => {
const folders = line.split('/');
vertices.push({ key: line, label: folders.slice(-1)[0] });
if (folders.length > 1) {
edges.push({ from: folders.slice(0, -1).join('/'), to: line });
}
});
Loading