Compare commits

...

17 Commits
v2.5 ... main

Author SHA1 Message Date
Asif Bacchus 12ff81b91c feature(readme): update readme
- include monitoring multiple directories
2022-05-02 00:38:44 -06:00
Asif Bacchus 4b8e019b84 chore(ide): update docker build params 2022-05-02 00:38:16 -06:00
Asif Bacchus 6970776aa8 feature: watch 5 directories vs 1 2022-05-02 00:31:19 -06:00
Asif Bacchus a17a9d38fd refactor(readme): update readme
- add changelog section
- reformat file
2022-02-26 22:13:08 -07:00
Asif Bacchus f1b0dc4c8b chore(ide): update docker build args 2022-02-26 22:12:51 -07:00
Asif Bacchus dc732efdb7 feature(dockerfile): multi-stage build
- install node dependencies in builder stage
- final stage based on alpine with minimal nodejs installation
- npm not present, prevents idiotic lingering security issues
- 50% smaller final image
2022-02-26 21:59:05 -07:00
Asif Bacchus ec07b94cd3 chore(ide): update docker build args 2022-02-26 20:49:52 -07:00
Asif Bacchus ef87879b60 chore(dockerfile): bump alpine base version 2022-02-26 20:46:28 -07:00
Asif Bacchus 48745eccbb chore(ide): add Rider docker build configuration 2022-02-26 20:46:09 -07:00
Asif Bacchus c6ccca24f7 update readme 2021-08-01 02:32:09 -06:00
Asif Bacchus 5bc0555579 chore(license): add license, import relevant licenses 2021-08-01 02:22:59 -06:00
Asif Bacchus 81267cdb7c fix(dockerfile): fix readme location in documentation label 2021-07-30 17:18:39 -06:00
Asif Bacchus f673f94283 fix(dockerfile): use tini to correct error code on exit
- node returns error on sigterm but this normal for docker termination
- coupled with javascript signal capture, tini ignores return 143,
reports 0
- allows for proper automatic restart since no error is reported
2021-07-30 17:10:37 -06:00
Asif Bacchus 5994f3b82e perf(dockerfile): moved copy file order
- moved node file copy order, allow for package.json usage
- invocation js moved after node install, faster builds
2021-07-30 17:07:46 -06:00
Asif Bacchus 106fe86cb9 feature(livereload): rewrite javascript: graceful async socket close
- rewrite javascript livereload script to use object for healthcheck
- aysnc operations shutting down healthcheck and livereload sockets
- handle signals properly
- fix error code reported by signals (node issue)
2021-07-30 17:06:05 -06:00
Asif Bacchus 9717e8a6fa refactor: rename repo, image, containers
- rename for integration with node-dev environment and production
deployment
- update image and product name across all files
- use generated project file to install node dependencies
- bump internal version to 2.6
2021-07-30 11:53:41 -06:00
Asif Bacchus c0a4fc1c6c fix(env): update env file to match new exclusion defaults 2021-07-29 22:53:51 -06:00
18 changed files with 1548 additions and 140 deletions

12
.env
View File

@ -1,6 +1,6 @@
#
# Parameters for node-livereload-tls stack:
# This file makes it easier to customize your node-livereload-tls stack deployment by providing centralized configuration options.
# Parameters for ab-livereload stack:
# This file makes it easier to customize your ab-livereload stack deployment by providing centralized configuration options.
# This file is *not required* since all values have (sane) default settings.
# There is *no* sensitive information in this file.
@ -81,12 +81,12 @@ TLS13_ONLY=TRUE
LR_EXTS="html,xml,css,js,jsx,ts,tsx,php,py"
# LR_EXCLUDE:
# Comma-delimited set of /regular-expressions/ defining what to exclude from monitoring in addition to the defaults.
# Upstream node-livereload lists the following as defaults: "/\.git\//,/\.svn\//,/\.hg\//"
# Comma-delimited set of regular-expressions defining what to exclude from monitoring in addition to the defaults.
# Upstream node-livereload already ignores: ".git/,.svn/,.hg/"
# REQUIRED: NO
# DEFAULT: "/\.vscode\//,/\.idea\//,/\.tmp/,/\.swp/"
# DEFAULT: ".vscode/,.idea/,.tmp$,.swp$"
# VALID OPTIONS: Any valid RegEx that matches files or directories
LR_EXCLUDE="/\.vscode\//,/\.idea\//,/\.tmp/,/\.swp/"
LR_EXCLUDE=".vscode/,.idea/,.tmp$,.swp$"
# LR_DELAY:
# Amount of time in milliseconds before detecting a change and sending a trigger for a browser reload. Useful if you need to allow time for background recompilation, etc.

3
.gitignore vendored
View File

@ -70,3 +70,6 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# node modules
build/node_modules

View File

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/contentModel.xml
/modules.xml
/.idea.ab-livereload.iml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxProjectSettings">
<option name="commitMessageIssueKeyValidationOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
<option name="commitMessageValidationConfigOverride">
<CommitMessageValidationOverride>
<option name="enabled" value="true" />
</CommitMessageValidationOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="Node.js Core" />
</component>
</project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownSettings">
<enabledExtensions>
<entry key="MermaidLanguageExtension" value="false" />
<entry key="PlantUMLLanguageExtension" value="false" />
</enabledExtensions>
</component>
</project>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CommitMessageInspectionProfile">
<profile version="1.0">
<inspection_tool class="BodyLimit" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SubjectBodySeparation" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SubjectLimit" enabled="true" level="ERROR" enabled_by_default="true" />
</profile>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,29 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="build/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker LOCAL">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="docker.asifbacchus.dev/ab-livereload/ab-livereload:4.0.0" />
<option name="buildArgs">
<list>
<DockerEnvVarImpl>
<option name="name" value="BUILD_DATE" />
<option name="value" value="2022-05-02" />
</DockerEnvVarImpl>
<DockerEnvVarImpl>
<option name="name" value="GIT_COMMIT" />
<option name="value" value="6970776aa8" />
</DockerEnvVarImpl>
<DockerEnvVarImpl>
<option name="name" value="INTERNAL_VERSION" />
<option name="value" value="4.0.0" />
</DockerEnvVarImpl>
</list>
</option>
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="build/Dockerfile" />
</settings>
</deployment>
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isPublishEnabled="true" />
<method v="2" />
</configuration>
</component>

43
LICENSE Normal file
View File

@ -0,0 +1,43 @@
AB-LIVERELOAD:
Copyright (c) 2021 Asif Bacchus <asif@asifbacchus.dev>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--------------------------
NODE-LIVERELOAD:
Copyright (c) 2010-2021 Brian P. Hogan and Joshua Peek
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,14 +1,7 @@
# node-livereload-tls (dockerized Livereload)
# ab-livereload (dockerized Livereload)
Containerized implementation of [node-livereload](https://www.npmjs.com/package/livereload) as forked by [Brian Hogan](https://github.com/napcs) ([github repo](https://github.com/napcs/node-livereload)). This container is based on Node running on Alpine and provides for easy version-pinning and node user UID/GID changes via build args. Time zone, monitored extensions, excluded files/directories and polling delays can be set via environment variables passed at runtime. The container runs under the non-root user *'node'* over the standard livereload port *35729* for compatibility with browser addons.
**VERSION 2.x: IMPORTANT CHANGES**
Starting with the 2.x version line, Ive added two *very* important features:
- SSL/TLS support with auto-generated self-signed certificates if you dont have your own certificates
- Healthcheck allowing for proper integration using docker-compose into a webstack
**Please note:** This container only generates notifications for livereload clients. It does NOT contain a webserver! Please see [Examples](#examples) and [Docker-Compose](#docker-compose) for how to add this to your webdev-stack.
## Contents
@ -19,26 +12,27 @@ Starting with the 2.x version line, Ive added two *very* important features:
- [Source/Issues](#sourceissues)
- [Environment variables](#environment-variables)
- [Volume mapping](#volume-mapping)
* [Certificate mount (HTTPS only)](#certificate-mount-https-only)
* [Content mount](#content-mount)
* [Certificate mount (HTTPS only)](#certificate-mount-https-only)
* [Content mount](#content-mount)
- [Commands](#commands)
- [Examples](#examples)
* [Run in HTTP (unsecured) mode](#run-in-http-unsecured-mode)
* [Run in HTTPS mode with supplied certificate](#run-in-https-mode-with-supplied-certificate)
* [Run in HTTPS mode with generated certificate](#run-in-https-mode-with-generated-certificate)
* [Run in HTTP (unsecured) mode](#run-in-http-unsecured-mode)
* [Run in HTTPS mode with supplied certificate](#run-in-https-mode-with-supplied-certificate)
* [Run in HTTPS mode with generated certificate](#run-in-https-mode-with-generated-certificate)
- [Livereload client](#livereload-client)
- [Permissions](#permissions)
* [Option 1: rebuild with different UID/GID](#option-1-rebuild-with-different-uidgid)
* [Option 2: specify runtime GID](#option-2-specify-runtime-gid)
* [Using Lets Encrypt](#using-lets-encrypt)
* [Option 1: rebuild with different UID/GID](#option-1-rebuild-with-different-uidgid)
* [Option 2: specify runtime GID](#option-2-specify-runtime-gid)
* [Using Lets Encrypt](#using-lets-encrypt)
- [Docker-Compose](#docker-compose)
- [Brief changelog](#brief-changelog)
- [Final thoughts](#final-thoughts)
<!-- tocstop -->
## Private docker repository
If you prefer, you can also use my private repository to download possibly newer containers. Simply change `asifbacchus/livereload:tag` to `docker.asifbacchus.dev/livereload/livereload:tag`.
If you prefer, you can also use my private repository to download possibly newer containers. Simply change `asifbacchus/livereload:tag` to `docker.asifbacchus.dev/ab-livereload/ab-livereload:tag`.
## Source/Issues
@ -48,16 +42,16 @@ If you want the Dockerfile or if you want to bring an issue/request to my attent
All environment variables have sensible defaults and, thus, are *not* required to be set for the container to run successfully.
| variable | description | default |
| ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| TZ | Set the container's time zone. NO impact on runtime, included for convenience. | Etc/UTC |
| LR_PORT | Port over which Livereload will communicate. All clients presently expect port 35729, so I suggest leaving this alone. | 35729 |
| LR_EXTS | Defines monitored extensions. | html,xml,css,js,jsx,ts,tsx,php,py |
| LR_EXCLUDE | Comma-delimited regular-expressions (Regex) that define paths or files to ignore. These are *appended* to the node-livereload upstream defaults which ignore everything in the `.git/`, `.svn/` and `.hg/` directories.<br />**N.B.** You do *not* have to use JavaScript format. The script will automatically convert things to JS-RegEx. You do, however, need to escape any special characters. | .vscode/,.idea/,.tmp$,.swp$/ |
| LR_DELAY | Time (ms) between polling for changed files. | 500 |
| LR_DEBUG | Print informational messages to the console. Allows you to see Livereload working. | true |
| LR_HTTPS | Use HTTPS and WSS. In other words, use a certificate for SSL/TLS operation. | true |
| CERT_HOSTNAME | If the container needs to generate a self-signed certificate, this is the hostname it will use. | Container hostname -- this almost *never* what you really want so dont use this default. |
| variable | description | default |
|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
| TZ | Set the container's time zone. NO impact on runtime, included for convenience. | Etc/UTC |
| LR_PORT | Port over which Livereload will communicate. All clients presently expect port 35729, so I suggest leaving this alone. | 35729 |
| LR_EXTS | Defines monitored extensions. | html,xml,css,js,jsx,ts,tsx,php,py |
| LR_EXCLUDE | Comma-delimited regular-expressions (Regex) that define paths or files to ignore. These are *appended* to the node-livereload upstream defaults which ignore everything in the `.git/`, `.svn/` and `.hg/` directories.<br />**N.B.** You do *not* have to use JavaScript format. The script will automatically convert things to JS-RegEx. You do, however, need to escape any special characters. | .vscode/,.idea/,.tmp$,.swp$/ |
| LR_DELAY | Time (ms) between polling for changed files. | 500 |
| LR_DEBUG | Print informational messages to the console. Allows you to see Livereload working. | true |
| LR_HTTPS | Use HTTPS and WSS. In other words, use a certificate for SSL/TLS operation. | true |
| CERT_HOSTNAME | If the container needs to generate a self-signed certificate, this is the hostname it will use. | Container hostname -- this almost *never* what you really want so dont use this default. |
## Volume mapping
@ -78,16 +72,18 @@ If you are mounting existing certificates:
Obviously, this container needs something to monitor to determine whether changes have been made. This is accomplished via bind-mounting a directory from the host and is why 'polling' is necessary. Mount a directory with files to be monitored to */watch* in the container.
> Starting with v4.0.0 you can watch up to 5 directories! Simply mount them to `/watch`, `/watch2` ... `/watch5'.
## Commands
The containers entrypoint script recognizes a few commands that tell it what you want to do:
| command | description |
| --------- | ------------------------------------------------------------ |
| listen | Activate Livereload server using configured parameters.<br />Aliases: run \| server \| start<br />`docker run --rm ... asifbacchus/livereload listen` |
| shell | Start container but drop to an Ash shell. Alternatvely, if you supply a command, the container will run that command in the shell, output results and then exit.<br />`docker run -it --rm ... asifbacchus/livereload shell`<br />`docker run --rm ... asifbacchus/livereload shell ls -lAsh /certs` |
| command | description |
|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| listen | Activate Livereload server using configured parameters.<br />Aliases: run \ | server \| start<br />`docker run --rm ... asifbacchus/livereload listen` |
| shell | Start container but drop to an Ash shell. Alternatvely, if you supply a command, the container will run that command in the shell, output results and then exit.<br />`docker run -it --rm ... asifbacchus/livereload shell`<br />`docker run --rm ... asifbacchus/livereload shell ls -lAsh /certs` |
| new-cert | Generate a new self-signed certificate with CN=CERT_HOSTNAME and matching DNS.1 value. Certificate and private key will be stored in */certs* as *fullchain.pem* and *privkey.pem*, respectively.<br />I strongly suggest running the container with `--user "uid:gid"` where the *gid* corresponds to one matching your webserver user, for example. That way your webserver would have read access to the generated private key. More information in the [Permissions](#permissions) section.<br />For example, running `docker run --rm -u "9999:6001" -v /etc/mycerts:/certs -e CERT_HOSTNAME=sub.domain.tld asifbacchus/livereload new-cert` would generate a new certificate and key pair in the */etc/mycerts/* directory on the host. Importantly, the private key would be readable by GID 6001 which, in this example, might be your webdev programs group including your webserver and you as the web-dev. |
| show-cert | Display the currently loaded certificate. This can be either a generated or a supplied certificate. Great way to confirm you mounted the right one!<br />`docker run --rm -v /etc/mycerts:/certs asifbacchus/livereload show-cert` |
| show-cert | Display the currently loaded certificate. This can be either a generated or a supplied certificate. Great way to confirm you mounted the right one!<br />`docker run --rm -v /etc/mycerts:/certs asifbacchus/livereload show-cert` |
## Examples
@ -143,18 +139,20 @@ There arent a lot of currently updated Livereload clients and/or browser addo
If you are running in an HTTP-permissive environment then lucky you! You can run this container in HTTP mode (`LR_HTTPS=false`) and use any of the clients and addons out there. If you want to use a snippet in your code instead of a client, simply insert this in the `<head>` of your page while using Livereload during dev:
```html
<script>
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>')
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>')
</script>
```
If, however, you are like me and want/need to use HTTPS then things are a little different. As I said, I cant find a single client or addon that works over HTTPS. Therefore, you *must* use a snippet in your webpage. Its the exact same as above, just use HTTPS instead -- again inserting in the `<head>` of your page:
```html
<script>
document.write('<script src="https://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>')
document.write('<script src="https://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>')
</script>
```
@ -232,6 +230,21 @@ docker run --rm ... -v /etc/letsencrypt/live/certname/fullchain.pem:/certs/fullc
Containers, like people, often get lonely and enjoy working with others. In the case of this container, it is quite useless if not paired with at least a web server. Ive included the core of the actual set up I use for web development -- a customized NGINX container and this Livereload container all secured with a certificate so everything even in testing is working over TLS like in real life. Take a look at the *docker-compose.yml* for more details. If youre using Lets Encrypt certificates, read the section above and remember to mount the files individually. If you are interested in my AB-NGINX container which has several useful additions to the official container including a healthcheck, then [check out the repo](https://git.asifbacchus.dev/ab-docker/ab-nginx).
## Brief changelog
### Version 3.0.0
- `npm` no longer present in final build, too many un-patched security vulnerabilities.
- multi-stage build with the final image being a minimal node installation directly on the Alpine base.
- container is now ~50% smaller due to multi-stage build :-)
### Version 2.x
Starting with the 2.x version line, Ive added two *very* important features:
- SSL/TLS support with auto-generated self-signed certificates if you dont have your own certificates
- Healthcheck allowing for proper integration using docker-compose into a webstack
## Final thoughts
That's it. Hopefully this is useful for you and makes it easier to run a live-reload server without having to install node on your machine. As always, let me know if you have any issues/suggestions or if something isnt well documented by filing an issue on either git repo.

View File

@ -2,48 +2,56 @@
# allow dynamic building by specifying base image elements as build-args
ARG NODE_VERSION=16
ARG ALPINE_VERSION=3.14
FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION}
ARG ALPINE_VERSION=3.15
FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} as builder
ARG NODE_VERSION
ARG ALPINE_VERSION
# install node dependences
WORKDIR /build
COPY [ "package.json", "package-lock.json", "./" ]
RUN npm ci --production
# final container
FROM alpine:${ALPINE_VERSION} as final
ARG NODE_VERSION
ARG ALPINE_VERSION
# create new node user with set UID and GID from build-args and create volume directories
ARG NODE_UID=9999
ARG NODE_GID=9999
RUN deluser --remove-home node \
&& addgroup -g ${NODE_GID} -S node \
RUN addgroup -g ${NODE_GID} -S node \
&& adduser -G node -S -u ${NODE_UID} node \
&& mkdir /watch /certs \
&& mkdir /watch /watch2 /watch3 /watch4 /watch5 /certs \
&& chown root:node /certs \
&& chmod 770 /certs
# create default volumes in-case user forgets, expose default port
# create default volumes in case user forgets, expose default port
VOLUME [ "/watch", "/certs" ]
EXPOSE 35729
# add tini, timezone support and create certificate directories
# add tini, timezone support, nodejs and create certificate directories
RUN apk --update --no-cache add \
tini \
tzdata \
openssl \
nodejs~${NODE_VERSION} \
&& apk --update --no-cache upgrade
# labels
MAINTAINER Asif Bacchus <asif@asifbacchus.dev>
LABEL maintainer="Asif Bacchus <asif@asifbacchus.dev>"
LABEL dev.asifbacchus.docker.internalName="node-livereload-tls"
LABEL dev.asifbacchus.docker.internalName="ab-livereload"
LABEL org.opencontainers.image.authors="Asif Bacchus <asif@asifbacchus.dev>"
LABEL org.opencontainers.image.description="Dockerized node-livereload supporting TLS and running under limited user account. Environment variables allow specifying files to watch/exclude and notification delay."
LABEL org.opencontainers.image.documentation="https://git.asifbacchus.dev/ab-docker/livereload/raw/branch/master/README.md"
LABEL org.opencontainers.image.source="https://git.asifbacchus.dev/ab-docker/livereload.git"
LABEL org.opencontainers.image.title="node-livereload-tls"
LABEL org.opencontainers.image.url="https://git.asifbacchus.dev/ab-docker/livereload"
LABEL org.opencontainers.image.vendor="NODE.js, node-livereload"
LABEL org.opencontainers.image.documentation="https://git.asifbacchus.dev/ab-docker/ab-livereload/raw/branch/main/README.md"
LABEL org.opencontainers.image.source="https://git.asifbacchus.dev/ab-docker/ab-livereload.git"
LABEL org.opencontainers.image.title="ab-livereload"
LABEL org.opencontainers.image.url="https://git.asifbacchus.dev/ab-docker/ab-livereload"
LABEL org.opencontainers.image.vendor="Asif Bacchus <asif@asifbacchus.dev>"
# default environment variables
ENV NODE_ENV=production
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
ENV PATH=/home/node/.npm-global/bin:$PATH
ENV TZ="Etc/UTC"
ENV LR_PORT=35729
ENV LR_EXTS="html,xml,css,js,jsx,ts,tsx,php,py"
@ -53,21 +61,14 @@ ENV LR_DEBUG=true
ENV LR_HTTPS=true
ENV CERT_HOSTNAME=""
# install node-livereload and express as node user then switch back to root user
USER node
# set-up application and copy dependencies from builder
WORKDIR /home/node
RUN mkdir -p .npm-global/bin .npm-global/lib \
&& npm config set fund false \
&& npm config set update-notifier false \
&& npm install livereload express --save
# copy scripts and fix-up all permissions
USER root
COPY [ "selfsigned.cnf", "/etc/selfsigned.cnf" ]
COPY [ "livereload.js", "/home/node/livereload.js" ]
COPY [ "entrypoint.sh", "/usr/local/bin/entrypoint.sh" ]
RUN chown node:node /home/node/livereload.js \
&& chmod 644 /home/node/livereload.js \
COPY --chown=node:node [ "ab-livereload.js", "/home/node/"]
COPY --from=builder [ "/build/node_modules", "/home/node/node_modules" ]
RUN chown -R node:node /home/node/* \
&& chmod 644 /home/node/ab-livereload.js \
&& chmod 755 /usr/local/bin/entrypoint.sh \
&& chmod 644 /etc/selfsigned.cnf
@ -81,7 +82,7 @@ HEALTHCHECK \
# switch to node user, run entrypoint script by default
USER node
WORKDIR /home/node
ENTRYPOINT [ "/sbin/tini", "--", "/usr/local/bin/entrypoint.sh" ]
ENTRYPOINT [ "/sbin/tini", "-e", "143", "--", "/usr/local/bin/entrypoint.sh" ]
# set build timestamp and version labels
ARG INTERNAL_VERSION

100
build/ab-livereload.js Normal file
View File

@ -0,0 +1,100 @@
/*
Implement node-livereload over HTTP or HTTPS connection with integrated
health-check, signal handling and graceful socket shutdown.
*/
// load required modules
const livereload = require('livereload');
const fs = require('fs');
const http = require('http');
// health check object
const healthCheck = {
app: healthCheckApp(),
server: function () {
return http.createServer(this.app);
},
start: function () {
this.server().listen(3000);
},
stop: function (callback) {
this.server().close(callback());
}
};
// set LiveReload server options
const extraExclusions = process.env.LR_EXCLUDE.split(",");
extraExclusions.forEach((exclusion, idx) => {
extraExclusions[idx] = new RegExp(exclusion);
});
// noinspection SpellCheckingInspection
const lrOptions = {
port: process.env.LR_PORT,
exts: process.env.LR_EXTS,
exclusions: extraExclusions,
usePolling: true,
delay: process.env.LR_DELAY
};
if (process.env.LR_DEBUG === 'true') {
lrOptions.debug = true;
console.log("[Debug output ENABLED]");
}
if (process.env.LR_HTTPS === 'true') {
lrOptions.https = {
cert: fs.readFileSync('/certs/fullchain.pem'),
key: fs.readFileSync('/certs/privkey.pem')
};
console.log("[HTTPS mode]");
}
else {
console.log("[HTTP mode]");
}
// start LiveReload server
// noinspection JSVoidFunctionReturnValueUsed
const lrServer = livereload.createServer(lrOptions, healthCheck.start());
lrServer.watch(['/watch', '/watch2', '/watch3', '/watch4', '/watch5']);
// graceful termination on signals
const termSignals = {
'SIGHUP': 1,
'SIGINT': 2,
'SIGTERM': 15
};
const shutdown = async (signal, value) => {
console.log("shutting down...\n");
await lrServer.close();
await healthCheck.stop(() => {
console.log("health-check STOPPED\n");
});
console.log(`server stopped after receiving ${signal}(${value}).`);
}
// iterate signals and create listener for each
Object.keys(termSignals).forEach((signal) => {
process.on(signal, () => {
console.log("\n! received signal:", signal, " !");
shutdown(signal, termSignals[signal]).then(() => {
process.exit(128 + termSignals[signal]);
});
});
});
//
// functions
function healthCheckApp() {
const express = require('express');
const app = express();
const router = express.Router();
router.use((req, res, next) => {
res.header('Access-Control-Allow-Methods', 'GET');
next();
});
router.get('/health', (req, res) => {
res.status(200).send('Ok');
});
return app.use('/api/v1', router);
}

View File

@ -1,7 +1,7 @@
#!/bin/sh
#
# entrypoint script for node-livereload-tls container
# entrypoint script for ab-livereload container
#
# functions
@ -105,7 +105,7 @@ esac
# action: run server
if [ "$doServer" -eq 1 ]; then
printf "Starting node-livereload-tls server:\n"
printf "Starting ab-livereload server:\n"
# https pre-flight check
if [ "$enableHTTPS" = "true" ]; then
@ -130,7 +130,7 @@ if [ "$doServer" -eq 1 ]; then
;;
esac
fi
exec node livereload.js
exec node ab-livereload.js
exit "$?"
fi

View File

@ -1,66 +0,0 @@
// implement node-livereload over an HTTP or HTTPS connection
function healthcheck() {
const express = require('express');
const http = require('http');
const app = express();
const router = express.Router();
router.use((req, res, next) => {
res.header('Access-Control-Allow-Methods', 'GET');
next();
});
router.get('/health', (req, res) => {
res.status(200).send('Ok');
});
app.use('/api/v1', router);
const hServer = http.createServer(app);
hServer.listen(3000);
}
// load modules
const livereload = require('livereload');
const fs = require('fs');
// process from environment variable as array and convert elements to RegEx objects
const extraExclusions = process.env.LR_EXCLUDE.split(",");
extraExclusions.forEach((exclusion, idx) => {
extraExclusions[idx] = new RegExp(exclusion);
});
// set createServer options
const options = {
port: process.env.LR_PORT,
exts: process.env.LR_EXTS,
exclusions: extraExclusions,
usePolling: true,
delay: process.env.LR_DELAY
};
// set debugging output as per LR_DEBUG
if (process.env.LR_DEBUG === "true") {
options.debug = true
console.log("[Debug output ENABLED]");
}
// set HTTPS as per LR_HTTPS
if (process.env.LR_HTTPS === "true") {
options.https = {
cert: fs.readFileSync('/certs/fullchain.pem'),
key: fs.readFileSync('/certs/privkey.pem')
};
console.log("[HTTPS mode]");
}
else {
console.log("[HTTP mode]");
}
// start server
const lrServer = livereload.createServer(options, healthcheck);
lrServer.watch('/watch')
//#EOF

1208
build/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

8
build/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "ab-livereload",
"version": "3.0.0",
"dependencies": {
"express": "^4.17.1",
"livereload": "^0.9.3"
}
}

View File

@ -1,5 +1,5 @@
#
# node-livereload-tls stack
# ab-livereload stack
#
version: '2.4'