github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/README.md (about)

     1  # Admin UI
     2  
     3  This directory contains the client-side code for CockroachDB's web-based admin
     4  UI, which provides details about a cluster's performance and health. See the
     5  [Admin UI docs](https://www.cockroachlabs.com/docs/stable/explore-the-admin-ui.html)
     6  for an expanded overview.
     7  
     8  ## Getting Started
     9  
    10  To start developing the UI, be sure you're able to build and run a CockroachDB
    11  node. Instructions for this are located in the top-level README. Every Cockroach
    12  node serves the UI, by default on port 8080, but you can customize the port with
    13  the `--http-port` flag. If you've started a node with the default options,
    14  you'll be able to access the UI at <http://localhost:8080>.
    15  
    16  Our UI is compiled using a collection of tools that depends on
    17  [Node.js](https://nodejs.org/) and are managed with
    18  [Yarn](https://yarnpkg.com), a package manager that offers more deterministic
    19  package installation than NPM. NodeJS 6.x and Yarn 1.7.0 are known to work.
    20  [Chrome](https://www.google.com/chrome/), Google's internet browser. Unit tests
    21  are run using Chrome's "Headless" mode.
    22  
    23  With Node and Yarn installed, bootstrap local development by running `make` in
    24  this directory. This will run `yarn install` to install our Node dependencies,
    25  run the tests, and compile the assets. Asset compilation happens in two steps.
    26  First, [Webpack](https://webpack.github.io) runs the TypeScript compiler and CSS
    27  preprocessor to assemble assets into the `dist` directory. Then, we package
    28  those assets into `embedded.go` using
    29  [go-bindata](https://github.com/kevinburke/go-bindata). When you later run `make
    30  build` in the parent directory, `embedded.go` is linked into the `cockroach`
    31  binary so that it can serve the admin UI when you run `cockroach start`.
    32  
    33  ## Developing
    34  
    35  When making changes to the UI, it is desirable to see those changes with data
    36  from an existing cluster without rebuilding and relaunching the cluster for each
    37  change. This is useful for rapidly visualizing local development changes against
    38  a consistent and realistic dataset.
    39  
    40  We've created a simple NodeJS proxy to accomplish this. This server serves all
    41  requests for web resources (JavaScript, HTML, CSS) out of the code in this
    42  directory, while proxying all API requests to the specified CockroachDB node.
    43  
    44  To use this proxy, in Cockroach's root directory run:
    45  ```shell
    46  $ make ui-watch TARGET=<target-cluster-http-uri>
    47  ```
    48  
    49  or, in `pkg/ui` run:
    50  ```shell
    51  $ make watch TARGET=<target-cluster-http-uri>
    52  ```
    53  
    54  then navigate to `http://localhost:3000` to access the UI.
    55  
    56  To proxy to a cluster started up in secure mode, in Cockroach's root directory run:
    57  ```shell
    58  $ make ui-watch-secure TARGET=<target-cluster-https-uri>
    59  ```
    60  
    61  or, in `pkg/ui` run:
    62  ```shell
    63  $ make watch-secure TARGET=<target-cluster-https-uri>
    64  ```
    65  
    66  then navigate to `https://localhost:3000` to access the UI.
    67  
    68  While the proxy is running, any changes you make in the `src` directory will
    69  trigger an automatic recompilation of the UI. This recompilation should be much
    70  faster than a cold compile—usually less than one second—as Webpack can reuse
    71  in-memory compilation artifacts from the last compile.
    72  
    73  If you get cryptic TypeScript compile/lint failures upon running `make` that
    74  seem completely unrelated to your changes, try removing `yarn.installed` and
    75  `node_modules` before re-running `make` (do NOT run `yarn install` directly).
    76  
    77  Be sure to also commit modifications resulting from dependency changes, like
    78  updates to `package.json` and `yarn.lock`.
    79  
    80  ### DLLs for speedy builds
    81  
    82  To improve Webpack compile times, we split the compile output into three
    83  bundles, each of which can be compiled independently. The feature that enables
    84  this is [Webpack's DLLPlugin](https://webpack.js.org/plugins/dll-plugin/), named
    85  after the Windows term for shared libraries ("**d**ynamic-**l**ink
    86  **l**ibraries").
    87  
    88  Third-party dependencies, which change infrequently, are contained in the
    89  [vendor DLL]. Generated protobuf definitions, which change more frequently, are
    90  contained in the [protos DLL]. First-party JavaScript and TypeScript are
    91  compiled in the [main app bundle], which is then "linked" against the two DLLs.
    92  This means that updating a dependency or protobuf only requires rebuilding the
    93  appropriate DLL and the main app bundle, and updating a UI source file doesn't
    94  require rebuilding the DLLs at all. When DLLs were introduced, the time required
    95  to start the proxy was reduced from over a minute to under five seconds.
    96  
    97  DLLs are not without costs. Notably, the development proxy cannot determine when
    98  a DLL is out-of-date, so the proxy must be manually restarted when dependencies
    99  or protobufs change. (The Make build system, however, tracks the DLLs'
   100  dependencies properly, so a top-level `make build` will rebuild exactly the
   101  necessary DLLs.) DLLs also make the Webpack configuration rather complicated.
   102  Still, the tradeoff seems well worth it.
   103  
   104  ## CCL Build
   105  
   106  In CCL builds, code in `pkg/ui/ccl/src` overrides code in `pkg/ui/src` at build
   107  time, via a Webpack import resolution rule. E.g. if a file imports
   108  `src/views/shared/components/licenseType`, it'll resolve to
   109  `pkg/ui/src/views/shared/components/licenseType` in an OSS build, and
   110  `pkg/ui/ccl/src/views/shared/components/licenseType` in a CCL build.
   111  
   112  CCL code can import OSS code by prefixing paths with `oss/`, e.g.
   113  `import "oss/src/myComponent"`. By convention, this is only done by a CCL file
   114  importing the OSS version of itself, e.g. to render the OSS version of itself
   115  when the trial period has expired.
   116  
   117  ## Running tests
   118  
   119  To run the tests outside of CI:
   120  
   121  ```shell
   122  $ make test
   123  ```
   124  
   125  ## Viewing bundle statistics
   126  
   127  The regular build also produces a webpage with a report on the bundle size.
   128  Build the app, then take a look with:
   129  
   130  ```shell
   131  $ make build
   132  $ open pkg/ui/dist/stats.ccl.html
   133  ```
   134  
   135  Or, to view the OSS bundle:
   136  
   137  ```shell
   138  $ make buildoss
   139  $ open pkg/ui/dist/stats.oss.html
   140  ```
   141  
   142  ## Bundling fonts
   143  
   144  To comply with the SIL Open Font License, we have reproducible builds of our WOFF
   145  font bundles based on the original TTF files sourced from Google Fonts.
   146  
   147  To rebuild the font bundles (perhaps to bring in an updated version of a typeface),
   148  simply run `make fonts` in the UI directory (or `make ui-fonts` elsewhere).  This
   149  requires `fontforge` to be available on your system.  Then validate the updated
   150  fonts and commit them.
   151  
   152  To add a new typeface, edit the script `scripts/font-gen` to fetch and convert it,
   153  and then add it to `styl/base/typography.styl` to pull it into the bundle.
   154  
   155  ## Managing dependencies
   156  
   157  The NPM registry (and the Yarn proxy in front of it) have historically proven
   158  quite flaky. Errors during `yarn install` were the leading cause of spurious CI
   159  failures in the first half of 2018.
   160  
   161  The solution is to check our JavaScript dependencies into version control, like
   162  we do for our Go dependencies. Checking in the entire node_modules folder is a
   163  non-starter: it clocks in at 230MB and 28k files at the time of writing.
   164  Instead, we use a Yarn feature called the [offline mirror]. We ship a [.yarnrc]
   165  file that instructs Yarn to save a tarball of each package we depend on in the
   166  [yarn-vendor] folder. These tarballs are then checked in to version control. To
   167  avoid cluttering the main repository, we've made the yarn-vendor folder a Git
   168  submodule that points at the [cockroachdb/yarn-vendored] repository.
   169  
   170  ### Adding a dependency
   171  
   172  Let's pretend you want to add a dependency on `left-pad`. Just use `yarn add`
   173  like you normally would:
   174  
   175  ```bash
   176  $ cd $GOPATH/src/github.com/cockroachdb/cockroach/pkg/ui
   177  $ yarn add FOO
   178  ```
   179  
   180  When Yarn finishes, `git status` will report something like this:
   181  
   182  ```bash
   183  $ git status
   184  Changes not staged for commit:
   185  	modified:   pkg/ui/package.json
   186  	modified:   pkg/ui/yarn-vendor (untracked content)
   187  	modified:   pkg/ui/yarn.lock
   188  ```
   189  
   190  The changes to package.json and yarn.lock are the normal additions of the new
   191  dependency information to the manifest files. The changes to yarn-vendor are
   192  unique to the offline mirror mode. Let's look more closely:
   193  
   194  ```bash
   195  $ git -C yarn-vendor status
   196  Untracked files:
   197  	left-pad-1.3.0.tgz
   198  ```
   199  
   200  Yarn has left you a tarball of the new dependency. Perfect! If you were adding
   201  a more complicated dependency, you'd likely see some transitive dependencies
   202  appear as well.
   203  
   204  The process from here is exactly the same as updating any of our other vendor
   205  submodules. Make a new branch in the submodule, commit the new tarball, and push
   206  it:
   207  
   208  ```bash
   209  $ cd yarn-vendor
   210  $ git checkout -b YOURNAME/add-left-pad
   211  $ git add .
   212  $ git commit -m 'Add left-pad@1.3.0'
   213  $ git push origin add-left-pad
   214  ```
   215  
   216  Be sure to push to [cockroachdb/yarn-vendored] directly instead of a personal
   217  fork. Otherwise TeamCity won't be able to find the commit.
   218  
   219  Then, return to the main repository and commit the changes, including the new
   220  submodule commit. Push that and make a PR:
   221  
   222  ```bash
   223  $ cd ..
   224  $ git checkout -b add-left-pad
   225  $ git add pkg/ui
   226  $ git commit -m 'ui: use very smart approach to pad numbers with zeros'
   227  $ git push YOUR-REMOTE add-left-pad
   228  ```
   229  
   230  This time, be sure to push to your personal fork. Topic branches are not
   231  permitted in the main repository.
   232  
   233  When your PR has been approved, please be sure to merge your change to
   234  yarn-vendored to master and delete your topic branch:
   235  
   236  ```bash
   237  $ cd yarn-vendor
   238  $ git checkout master
   239  $ git merge add-left-pad
   240  $ git push origin master
   241  $ git push origin -d add-left-pad
   242  ```
   243  
   244  This last step is extremely important! Any commit in yarn-vendored that is
   245  referenced by the main repository must remain forever accessible, or it will be
   246  impossible for future `git clone`s to build that version of Cockroach. GitHub
   247  will garbage collect commits that are not accessible from any branch or tag, and
   248  periodically, someone comes along and cleans up old topic branches in
   249  yarn-vendored, potentially removing the only reference to a commit. By merging
   250  your commit on master, you ensure that your commit will not go missing.
   251  
   252  ### Verifying offline behavior
   253  
   254  Our build system is careful to invoke `yarn install --offline`, which instructs
   255  Yarn to exit with an error if it would need to reach out to the network. Running
   256  CI on your PR is thus sufficient to verify that all dependencies have been
   257  vendored correctly.
   258  
   259  You can perform the verification locally if you'd like, though:
   260  
   261  ```bash
   262  $ cd $GOPATH/src/github.com/cockroachdb/cockroach/pkg/ui
   263  $ rm -r node_modules yarn.installed
   264  $ yarn cache clean
   265  $ make
   266  ```
   267  
   268  If `make` succeeds, you've vendored dependencies correctly.
   269  
   270  ### Removing a dependency
   271  
   272  To remove a dependency, just run `yarn remove`.
   273  
   274  Note that removing a dependency will not remove its tarball from the yarn-vendor
   275  folder. This is not as bad as it sounds. When Git fetches submodules, it always
   276  performs a full clone, so it would wind up downloading deleted tarballs anyway
   277  when it fetched older commits.
   278  
   279  TODO(benesch): Yarn's offline mode has an additional option,
   280  `yarn-offline-mirror-pruning`, that cleans up removed dependencies' tarballs.
   281  Look into using this once [dcodeIO/protobuf.js#716] is resolved. At the moment,
   282  ProtobufJS tries to install some dependencies at runtime by invoking `npm
   283  install` itself (!); we avoid this by running `yarn install` on its behalf, but
   284  this means two separate packages share the same yarn-vendor folder and this
   285  confuses Yarn's pruning logic.
   286  
   287  If the size of the yarn-vendored repository becomes problematic, we can look
   288  into offloading the large files into something like [Git LFS]. This is
   289  contingent upon resolving the above TODO.
   290  
   291  [cockroachdb/yarn-vendored]: https://github.com/cockroachdb/yarn-vendored
   292  [dcodeIO/protobuf.js#716]: https://github.com/dcodeIO/protobuf.js#716
   293  [main app bundle]: ./webpack.app.js
   294  [Git LFS]: https://git-lfs.github.com
   295  [offline mirror]: https://yarnpkg.com/blog/2016/11/24/offline-mirror/
   296  [protos DLL]: ./webpack.protos.js
   297  [vendor DLL]: ./webpack.vendor.js
   298  [.yarnrc]: ./yarnrc
   299  [yarn-vendor]: ./yarn-vendor