Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 48 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Example widgets that use this framework:
* **[rhtmlMoonPlot](https://github.com/Displayr/rhtmlMoonPlot)**: a widget for displaying a moon plot to visualise results of correspondance analysis
* **[rhtmlSankeyTree](https://github.com/Displayr/rhtmlSankeyTree)**: a widget for displaying sankey diagrams

HTML Widgets that use the `rhtmlBuildUtils` package are ES2015 (or greater) based nodejs projects that use gulp as a task manager. The twofold purpose(s) of these nodejs projects is to produce R HTMLWidget package for cunsumption in R, and provide a development framework including a visual regression suite to make development easier.
HTML Widgets that use the `rhtmlBuildUtils` package are ES2015 (or greater) based nodejs projects whose build tasks are run by the `rhtml` binary this package installs. The twofold purpose(s) of these nodejs projects is to produce R HTMLWidget package for cunsumption in R, and provide a development framework including a visual regression suite to make development easier.

## Documentation

Expand All @@ -36,30 +36,48 @@ In your widget repo directory run :

npm install -D "github:Displayr/rhtmlBuildUtils#9.0.0"

then in your project gulpfile.js:
then add an `eslint.config.js` in your widget repo root:

const gulp = require('gulp')
const rhtmlBuildUtils = require('rhtmlBuildUtils')

const dontRegisterTheseTasks = []
rhtmlBuildUtils.registerGulpTasks({
gulp: gulp,
exclusions: dontRegisterTheseTasks
})
module.exports = require('rhtmlBuildUtils/eslint.config.base')

and an `eslint.config.js` in your widget repo root:
and invoke the tasks through the `rhtml` binary from your npm scripts:

module.exports = require('rhtmlBuildUtils/eslint.config.base')
"scripts": {
"build": "rhtml build",
"lint": "rhtml lint",
"start": "rhtml serve",
"localTest": "rhtml testSpecs && rhtml testVisual --env=local"
}

There is no gulpfile.js and no registration step: the tasks in [src/tasks](src/tasks) are discovered
automatically and are enumerated [below](#task-reference).

### Upgrading to 9.0.0 from 8.x

9.0.0 moves to eslint 10, which **removed `.eslintrc` support entirely**. A widget repo must therefore
replace its `.eslintrc` (and `.eslintignore`, which flat config also drops) with the one line
`eslint.config.js` shown above; without it `gulp lint` fails with "couldn't find an eslint
configuration file". The shared config reproduces the previous `standard` style, so adopting it should
not reformat any widget code. eslint 10 also requires node `^20.19.0 || ^22.13.0 || >=24`.
Two breaking changes, both requiring a small edit in the widget repo.

**1. gulp is gone.** Delete your `gulpfile.js`, drop `gulp` from your devDependencies, and change every
npm script from `gulp <task>` to `rhtml <task>`. Task names, sequences and command line flags are all
unchanged, so `gulp testVisual --env=local --branch=x` becomes `rhtml testVisual --env=local
--branch=x`. If your repo defines its OWN gulp tasks (rhtmlDonut does), keep gulp as a dependency of
your repo for those and use `rhtml` for the shared ones.

Excluding a task no longer means passing `exclusions` or re-registering it as a no-op. Set
`disabledTasks` in `build/config/widget.config.js` instead:

disabledTasks: ['testSpecs']

**2. eslint 10 removed `.eslintrc` support entirely.** Replace your `.eslintrc` (and `.eslintignore`,
which flat config also drops) with the one line `eslint.config.js` above; without it `rhtml lint` fails
with "couldn't find an eslint configuration file". The shared config reproduces the previous `standard`
style, so adopting it should not reformat any widget code.

eslint 10 also requires node `^20.19.0 || ^22.13.0 || >=24`.

By calling registerGulpTasks you will add all the tasks defined in [src/tasks](src/tasks) to your project. These tasks are enumerated [below](#gulp-task-reference).
Build output is unchanged by the gulp removal: the generated `browser/`, `inst/` and `R/` trees are
byte for byte identical to what the gulp pipeline produced, which is deliberate, because the compiled
css feeds the pages the visual regression suite screenshots. `less` is pinned to 3.13.1 (the version
`gulp-less@4` resolved) to keep it that way.

Two of the main features provided by rhtmlBuildUtils are to start the internal web server and to run the visual regression tests. These topics are covered in these subdocs:

Expand All @@ -70,11 +88,11 @@ The `rhtmlBuildUtils` makes many assumptions about the directory structure and n

## Customisation

When using the `rhtmlBuildUtils` package in a widget repo, there are two ways to change the behaviour of the gulp tasks: to exclude a task then define it yourself in the repo, or to modify a local widget.config.js file.
When using the `rhtmlBuildUtils` package in a widget repo, there are two ways to change the behaviour of the tasks: disable a task, or modify a local widget.config.js file.

### Override a task in a repo
### Disable a task in a repo

When calling rhtmlBuildUtils.registerGulpTasks, pass an exclusions array with a list of tasks that you do not want rhtmlBuildUtils to define. Then add them to your gulp config following standard gulp techniques; see [http://gulpjs.com/](http://gulpjs.com/).
List the task names in `disabledTasks` in `build/config/widget.config.js`. A disabled task logs `skipping '<name>'` and resolves, so any composite sequence that contains it still completes. This replaces both the `exclusions` argument to the old registerGulpTasks and the idiom of re-registering a task as a no-op.

### Modifying widget.config.js

Expand All @@ -93,15 +111,15 @@ Example:
loader: { '.js': 'jsx' }
}

# gulp task reference
# task reference

## Top Level Tasks

The top level tasks are those you will likely run as part of the widget build process:

`gulp` : this will run the default task: `gulp build`
`rhtml` : this will run the default task: `rhtml build`

`gulp build` : the following tasks are performed :
`rhtml build` : the following tasks are performed :

* delete the directories that contain auto generated code
* run the JS style checker (eslint) and fail the build if the code does not match style
Expand All @@ -110,17 +128,17 @@ The top level tasks are those you will likely run as part of the widget build pr
* copy all images and other resources into the dist directories
* write R docs

`gulp serve` : the following tasks are performed :
`rhtml serve` : the following tasks are performed :

* all of the build tasks above (except test and lint)
* produce a different transpiled version of the code that will load in a local browser
* in addition to the HTML Widget libraries, the local browser session will include a list of examples. This allows the developer to view the effect of their changes
* if this repo contains any experiments, the experiment results will be browsable in the local browser
* gulp serve also starts a `watch` process. Every save to the local file system will rebuild the project and then send a signal to the browser to reload the active page, so that the changes just made to the project are immediately visible.
* `rhtml serve` also starts a `watch` process. Every save to the local file system will rebuild the project and then send a signal to the browser to reload the active page, so that the changes just made to the project are immediately visible.

`gulp testSpecs` : just run the spec tests
`rhtml testSpecs` : just run the spec tests

`gulp testVisual` : start server (`i.e., gulp serve`), take snapshots for each test definition. This command takes several parameters
`rhtml testVisual` : start server (i.e. `rhtml serve`), take snapshots for each test definition. This command takes several parameters

* **--acceptNewSnapshots**: accept new snapshots. Defaults to true
* **--branch**: which branch. This determines where to save updated snapshots, and which snapshot set to use for a baseline
Expand All @@ -131,9 +149,9 @@ The top level tasks are those you will likely run as part of the widget build pr
* **--testNamePattern**: run subset of tests using this string to filter snapshots. Can be file name or test name
* **--updateSnapshots**: accept all snapshots even if they have changed. Write the new snapshots into the snapshot directory

`gulp testVisual_s` : just run the visual regression suite (skip the other steps, `gulp serve` must already be running).
`rhtml testVisual_s` : just run the visual regression suite (skip the other steps, `rhtml serve` must already be running).

`gulp lint` : this runs the eslint style checker on all the javascript files. Our settings are defined in [eslint.config.base.js](./eslint.config.base.js), which your widget repo's `eslint.config.js` re-exports. Which files are checked is decided by the `ignores` in that config rather than by this task, because eslint 10 has no `.eslintignore`. To run with auto fix run `gulp lint --fix`. Note that this is also run as a git prepush hook so you will not be able to push code to git unless it passes the style checks.
`rhtml lint` : this runs the eslint style checker on all the javascript files. Our settings are defined in [eslint.config.base.js](./eslint.config.base.js), which your widget repo's `eslint.config.js` re-exports. Which files are checked is decided by the `ignores` in that config rather than by this task, because eslint 10 has no `.eslintignore`. To run with auto fix run `rhtml lint --fix`. Note that this is also run as a git prepush hook so you will not be able to push code to git unless it passes the style checks.

# Developing / Contributing

Expand Down
2 changes: 2 additions & 0 deletions bin/rhtml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require('../src/cli')
6 changes: 3 additions & 3 deletions docs/experiment_framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ TODO Examples of the framework

# Quick Refererence

* run an experiment: `gulp runExperiment --name EXPERIMENT_NAME`
* skip the baseline: `gulp runExperiment --no-baseline --name EXPERIMENT_NAME`
* run only a specific iteration of an experiment: `gulp runExperiment --iteration ITERATION_NAME --no-baseline --name EXPERIMENT_NAME`
* run an experiment: `rhtml runExperiment --name EXPERIMENT_NAME`
* skip the baseline: `rhtml runExperiment --no-baseline --name EXPERIMENT_NAME`
* run only a specific iteration of an experiment: `rhtml runExperiment --iteration ITERATION_NAME --no-baseline --name EXPERIMENT_NAME`

# Required Files and Config

Expand Down
12 changes: 6 additions & 6 deletions docs/internal_web_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Quick Reference: how to run it and extend it

* to run the internal web server : `gulp serve`
* to run the internal web server : `rhtml serve`
* there are two ways to add new content to the web server:
* create a new file in `theSrc/internal_www/content` directory using the [content_template](https://github.com/Displayr/rhtmlTemplate/blob/master/theSrc/internal_www/content/content_template.html), or add an example to an existing content file IF IT FITS (dont mix concerns in your files)
* create a new yaml test plan file in `theSrc/test_plans` directory using the [test plan syntax](./test_plan_syntax.md) guide for instructions.
Expand All @@ -14,15 +14,15 @@ There are multiple objectives served by maintaining a set of internal content fo
* **Allow visual regression testing** : We can compare the content generated by two versions of the code to determine if anything unexpected has changed. This can be done manually via inspection of the content, or automatically using the [visual regression test suite](./visual_regression_testing.md).
* **Allow interaction testing** : We can write test that interact with the widget in the browser and verify certain things happen and the the final state matches a visual regression snapshot
* **Real time feedback during dev** : This allows a workflow where I write up a config for a widget that doesn't currently support what I am trying to do, then I start writing the code to support the new feature. Every time I save my work, the widget is redrawn, so I can see in real time how my work is progressing.
* **Maintain live documentation** : Using the internal web server framework it is straightforward to build tutorial style documentation, and even snapshot that documentation to ensure your docs dont break. See the [rhtmlPictographs](https://github.com/Displayr/rhtmlPictographs) tutorial section when running gulp serve in the rhtmlPictographs repo for a good example.
* **Maintain live documentation** : Using the internal web server framework it is straightforward to build tutorial style documentation, and even snapshot that documentation to ensure your docs dont break. See the [rhtmlPictographs](https://github.com/Displayr/rhtmlPictographs) tutorial section when running `rhtml serve` in the rhtmlPictographs repo for a good example.

### Why hav an internal web server ?

At first glance in the widget repos you see quite a bit of non production code so worth explaining why it is worth it. Consider the following scenario where I begin to add feature X to my widget. I add an example called _**feature X WIP**_ to the internal_www content area (i.e., /theSrc/internal_www/content) area. I run `gulp serve`, and navigate to the _**feature X WIP**_ example. It doesn't work :(. This makes sense though because I haven't even written the code yet ! I make a series of changes to implement feature X. Every time I save an update to my project files, gulp auto builds the code, and sends a reload signal to my browser. I am literally seeing the visual effects of my code changes in real time. _**This is really good**_.
At first glance in the widget repos you see quite a bit of non production code so worth explaining why it is worth it. Consider the following scenario where I begin to add feature X to my widget. I add an example called _**feature X WIP**_ to the internal_www content area (i.e., /theSrc/internal_www/content) area. I run `rhtml serve`, and navigate to the _**feature X WIP**_ example. It doesn't work :(. This makes sense though because I haven't even written the code yet ! I make a series of changes to implement feature X. Every time I save an update to my project files, the watch task auto builds the code, and sends a reload signal to my browser. I am literally seeing the visual effects of my code changes in real time. _**This is really good**_.

## How the browser area is built

The internal web server is just hosting all the files in the `browser` area, which is an auto generated section of the repo. Several gulp steps work in conjunction to build the content in the `browser` directory and serve it at http://127.0.0.1:9000. The 'important' ones are described below:
The internal web server is just hosting all the files in the `browser` area, which is an auto generated section of the repo. Several build tasks work in conjunction to build the content in the `browser` directory and serve it at http://127.0.0.1:9000. The 'important' ones are described below:

* the `compileRenderContentPage` and `compileRenderIndexPage` steps compiles ES6 into ES5 for the browser. These steps also convert the compileRenderContentPage.template.js into the compileRenderContentPage.js, adding widget specific config to the generic compileRenderContentPage.template.js to create a compileRenderContentPage.js specific for the widget under test. Same process for the index file
* the `copy` step copies all the html and image files from `theSrc/internal_www` into the `browser` area
Expand All @@ -45,7 +45,7 @@ There are several features provided by [renderContentPage.js](/src/tasks/webserv
It is easiest to grasp by looking at an example in the rhtmlTemplate app:

* look at the source of the example : [example_of_content_page_features.html](https://github.com/Displayr/rhtmlTemplate/blob/master/theSrc/internal_www/content/tutorials/example_of_content_page_features.html).
* After running `gulp serve` (in the rhtmlTemplate project, not in the rhtmlBuildUtils project), you can view the page [http://localhost:9000/content/tutorials/example_of_content_page_features.html](http://localhost:9000/content/tutorials/example_of_content_page_features.html).
* After running `rhtml serve` (in the rhtmlTemplate project, not in the rhtmlBuildUtils project), you can view the page [http://localhost:9000/content/tutorials/example_of_content_page_features.html](http://localhost:9000/content/tutorials/example_of_content_page_features.html).

**The web server content features:**

Expand Down Expand Up @@ -99,7 +99,7 @@ Note that adding `snapshot-name` also changes the css `display` property to `inl

The features provided by `renderContentPage.js` are listed above. Using `renderContentPage.js` we can write some HTML markup that causes widgets to be rendered. An alternative approach is to use [renderExample.html](../build/templates/renderExample.template.html), which will take all arguments as query parameters and render a single widget. This is useful for automated testing because we do not need to craft a HTML page to render a widget, instead we just pass arguments to `renderExample.html`.

When `gulp serve` is running the `renderExample.html` page is available at this URL : [http://localhost:9000/renderExample.html]
When `rhtml serve` is running the `renderExample.html` page is available at this URL : [http://localhost:9000/renderExample.html]

`renderExample.html` is in a state of flux. It used to accept the parameters listed below, but at present it will only accept a `config` query parameter whose value is a base64 encoded json payload. This was done to facilitate the new [test_plan style specifications in rhtmlDonut](https://github.com/Displayr/rhtmlDonut/tree/master/theSrc/test_plans). However when this change was made, backwards compatability was not maintained.

Expand Down
12 changes: 6 additions & 6 deletions docs/snapshotting_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

## Quick Reference: how to use and extend it

* to run the visual regression suite : `gulp testVisual`
* to run the visual regression suite if `gulp serve` is already running: `gulp testVisual_s`
* to run the visual regression suite on a subset of the tests : `gulp testVisual_s -t=FILTER`. Only tests whose name matches FILTER will be run
* to accept the current snapshots and override the existing snapshots (aka what I have is the new baseline): `gulp testVisual_s -u`
* to run the visual regression suite : `rhtml testVisual`
* to run the visual regression suite if `rhtml serve` is already running: `rhtml testVisual_s`
* to run the visual regression suite on a subset of the tests : `rhtml testVisual_s -t=FILTER`. Only tests whose name matches FILTER will be run
* to accept the current snapshots and override the existing snapshots (aka what I have is the new baseline): `rhtml testVisual_s -u`
* to view the visual regression results: look at the collection of snapshots in the `<projectRoot>/theSrc/test/snapshots` directory for the current env and git branch. For example if you are doing local development on a branch called VIS-778 then look in the `<projectRoot>/theSrc/test/snapshots/local/VIS-778` directory
* to see all the diffs for the failed snapshots:
* these diffs will be stored in `__diff_output__` directories in the `<projectRoot>/theSrc/test/snapshots/local/BRANCH` directory.
Expand All @@ -26,7 +26,7 @@
* follow the steps above to retrieve snapshots from travis-ci
* copy those snapshots into the `<projectRoot>/theSrc/test/snapshots/travis/master` directory

**Note:** that in some repos we define npm commands in the `package.json` file that "wrap" the gulp commands. So for example in the `rhtmlTemplate` and `rhtmlLabeledScatter` repos we can run the snapshot suite by running `npm run localTest`.
**Note:** that in some repos we define npm commands in the `package.json` file that "wrap" the `rhtml` commands. So for example in the `rhtmlTemplate` and `rhtmlLabeledScatter` repos we can run the snapshot suite by running `npm run localTest`.

## Technology Breakdown

Expand Down Expand Up @@ -164,4 +164,4 @@ The current process to update travis snapshots is pretty laborious:
* add to git and commit
* get green build

Proposal is to put something in the commit message that will cause the build to add the -u flag to the `gulp testVisual command`
Proposal is to put something in the commit message that will cause the build to add the -u flag to the `rhtml testVisual` command
Loading