Skip to content

Improve community site local dev workflow (fixes watch & hot-reloading)#1674

Open
bcullman wants to merge 4 commits intoOctopusDeploy:masterfrom
bcullman:improve-dev-qol
Open

Improve community site local dev workflow (fixes watch & hot-reloading)#1674
bcullman wants to merge 4 commits intoOctopusDeploy:masterfrom
bcullman:improve-dev-qol

Conversation

@bcullman
Copy link
Copy Markdown
Contributor

@bcullman bcullman commented Apr 9, 2026

Background

This PR improves the local development workflow for the Octopus Community Library (library.octopus.com) site.

The current local dev loop has several issues:

  • npm run watch opens the BrowserSync proxy URL instead of the primary app URL on port 9000
  • Once that is resolved, the browser can still open before the app is ready
  • edits to step template JSON files do not flow through the fastest possible rebuild path
  • regenerated step template data is not reliably served without restarting in development
  • client-side React edits do not always show up cleanly through the normal reload flow

Results

The local watch and hot-reload loop is now more reliable and closer to what a developer expects during day-to-day work.

Before

  • local watch opened the proxy URL instead of the main app URL
  • the browser could open before the app was reachable
  • step template edits used a heavier rebuild path
  • generated template data could stay stale until restart
  • React edits did not hot-reload reliably and could require a hard refresh to appear

After

  • local watch opens http://localhost:9000
  • the browser waits until the app is reachable before opening
  • step template edits use a narrower step-templates:data path
  • development reads refreshed generated template data without requiring a restart
  • React edits now hot-reload more reliably during local development
  • production behavior is kept tighter by caching template data outside development

Pre-requisites

  • Id should be a GUID that is not 00000000-0000-0000-0000-000000000000
    • NOTE If you are modifying an existing step template, please make sure that you do not modify the Id property (updating the Id will break the Library sync functionality in Octopus).
  • Version should be incremented, otherwise the integration with Octopus won't update the step template correctly
  • Parameter names should not start with $
  • Step template parameter names (the ones declared in the JSON, not the script body) should be prefixed with a namespace so that they are less likely to clash with other user-defined variables in Octopus (see this issue). For example, use an abbreviated name of the step template or the category of the step template).
  • LastModifiedBy field must be present, and (optionally) updated with the correct author
  • The best practices documented here have been applied
  • If a new Category has been created:
    • An image with the name {categoryname}.png must be present under the step-templates/logos folder
    • The switch in the humanize function in gulpfile.babel.js must have a case statement corresponding to it

Fixes #1673

@bcullman bcullman changed the title Improve local development workflow for watch and reload behavior Improve local development workflow for watch and hot-reloading Apr 9, 2026
@bcullman bcullman changed the title Improve local development workflow for watch and hot-reloading Improve local library.octopus.com dev workflow (fixes watch & hot-reloading) Apr 9, 2026
@bcullman bcullman changed the title Improve local library.octopus.com dev workflow (fixes watch & hot-reloading) Improve community site local dev workflow (fixes watch & hot-reloading) Apr 9, 2026
Comment thread gulpfile.babel.js
browserSync.init(null, {
proxy: "http://localhost:9000",
});
browserSync.init(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes watch to open the primary app URL on :9000 instead of the BrowserSync proxy, and waits until the server is reachable before opening the browser.

Comment thread gulpfile.babel.js
.pipe(argv.production ? gulp.dest(`${publishDir}/app/services`) : gulp.dest(`${buildDir}/app/services`));
})
);
gulp.task("step-templates:data", () => {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template edits now use the narrower step-templates:data path during watch, so local template changes refresh without rerunning the heavier full step-templates flow.

Comment thread app/services/LibraryDb.js
return this.hydrateTemplates(this.readTemplatesFromDisk());
}

getTemplates() {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In development, the library data is read fresh from disk so regenerated step-templates.json is served without restarting; non-development still uses cached in-memory data.

Comment thread server/server.js

let app = express();
const isDevelopment = process.env.NODE_ENV === "development";
const staticAssetOptions = isDevelopment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These dev-only no-cache headers avoid stale local assets during hot-reload, which previously made React changes appear only after a hard refresh.

Comment thread server/server.js

LibraryActions.sendTemplates(data, () => {
var libraryAppHtml = ReactDOMServer.renderToStaticMarkup(<RouterContext {...renderProps} />);
const browserSyncClientUrl = process.env.NODE_ENV === "development" ? `${req.protocol}://${req.hostname}:3000/browser-sync/browser-sync-client.js` : null;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

watch now opens the app directly on :9000, so this passes through the BrowserSync client URL to keep browser reloads working while using the app URL instead of the proxy URL.

Comment thread server/views/index.pug

ga('create', 'UA-24461753-5', 'octopusdeploy.com');

if browserSyncClientUrl
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inject the BrowserSync client into the app page during local development so reloads still work while browsing :9000 directly.

@bcullman
Copy link
Copy Markdown
Contributor Author

bcullman commented Apr 9, 2026

cc @twerthi @hnrkndrssn

@hnrkndrssn
Copy link
Copy Markdown
Contributor

Hey @bcullman thank you for you submission and my apologies for the slow response to your PR but we've been very busy the last few weeks so haven't had a chance to have a look at your PR yet.

I'll try and get to it early next week, as it requires local testing I need to find some time to fit it in.

@bcullman
Copy link
Copy Markdown
Contributor Author

bcullman commented Apr 17, 2026

@hnrkndrssn - understood. I am unsure your familiarity with this tooling, so I offer the following as an explicit set of instructions to aide in testing.

TL;DR

This branch improves the local watch experience in two ways:

  • It stops opening the browser to http://localhost:3000, which is not the actual reviewable UI.
  • It enables hot reload for both:
    • step-template JSON changes
    • React component changes

On master, those changes do not show up properly without stopping and restarting the watch process. On this branch, they do.

Before (master)

  • Run npm run setup
  • Run npm run watch
    • BrowserSync is created on port 3000
    • A browser is launched to http://localhost:3000
    • That is not the actual UI to review
    • The actual app is served from http://localhost:9000
    • There is also a small delay where port 3000 is up before port 9000 is ready
  • Manually change the browser URL to http://localhost:9000
    • You should now see the Community Library site

JSON file change does not hot reload

  • Leave the browser open to http://localhost:9000
  • Edit a step template. Any will do, but for this demo, choose step-templates\onepassword-retrieve-secrets.json
    • prepend ! to the Name value
    • This should move it to the top of the list alphabetically
  • Save the file and return to the browser
    • no automatic reload
    • manual browser refresh still does not show the change
    • navigating to the onepassword-retrieve-secrets.json page and choosing Show JSON also does not reflect the edit
  • Stop the watch process and run npm run watch again
  • Go back to http://localhost:9000
    • Now the change appears

React component change does not hot reload

  • Leave the browser open to http://localhost:9000
  • Edit a react component. . Any will do, but for this demo, choose app/components/footer.jsx
  • Make any visible HTML change
  • Save the file and return to the browser
    • no automatic reload
    • manual browser refresh still does not show the change
  • Stop the watch process and run npm run watch again
  • Go back to http://localhost:9000
    • Now the change appears

After (this branch)

  • Run npm run setup
  • Run npm run watch
    • BrowserSync is still created on port 3000
    • It does not open a browser to http://localhost:3000
    • It waits until port 9000 is ready
    • It then launches the browser directly to http://localhost:9000

JSON file change does hot reload

  • Leave the browser open to http://localhost:9000
  • Edit step-templates\onepassword-retrieve-secrets.json
    • For consistency, prepend ! to the Name value
  • Save the file and return to the browser
    • the browser automatically reloads
    • the edited template moves to the top of the list (due to alpha sorting)
    • navigating to the onepassword-retrieve-secrets.json page and choosing Show JSON reflects the edit
    • no restart of the watch process is needed

React component change does hot reload

  • Leave the browser open to http://localhost:9000
  • Edit app/components/footer.jsx
  • Make any visible HTML change
  • Save the file and return to the browser
    • the browser automatically reloads
    • the footer change is immediately visible (see note)
    • no restart of the watch process is needed

Note

Do not see the change immediately? this is because during this testing, you built this first on branch main, which puts react components in cache. This branch does not do this on the dev build.
So first time, you will need to shift-reload to see your changes. After that, this will work as expected - update a file, save, and see the results immediately in the browser.
Once this PR is merged, the cache behavior will be gone, and shift-reload will not be needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local development workflow can be improved

2 participants