From 75afb7718a3c0bae27ba257c34a15b1e11e3adf7 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 29 May 2020 17:01:42 -0500 Subject: [PATCH 01/33] Removed unused template --- views/layout.jade | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 views/layout.jade diff --git a/views/layout.jade b/views/layout.jade deleted file mode 100644 index 15af079b..00000000 --- a/views/layout.jade +++ /dev/null @@ -1,7 +0,0 @@ -doctype html -html - head - title= title - link(rel='stylesheet', href='/stylesheets/style.css') - body - block content From ae5564a86bd48122a2ad7b4e503c05c48f7313f0 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 29 May 2020 17:34:29 -0500 Subject: [PATCH 02/33] Use EJS for index page in dev. --- build/webpack.dev.conf.js | 7 ++++++- build/webpack.prod.conf.js | 15 --------------- config/app.js | 2 ++ index.html => views/index.ejs | 13 +++++++------ 4 files changed, 15 insertions(+), 22 deletions(-) rename index.html => views/index.ejs (54%) diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index cef3abca..f6879d98 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -2,6 +2,7 @@ const utils = require('./utils') const webpack = require('webpack') const config = require('../config') +const appConfig = require('../config/app'); const merge = require('webpack-merge') const path = require('path') const baseWebpackConfig = require('./webpack.base.conf') @@ -55,8 +56,12 @@ const devWebpackConfig = merge(baseWebpackConfig, { new webpack.NoEmitOnErrorsPlugin(), // https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ + title: 'ZWave To MQTT', filename: 'index.html', - template: 'index.html', + template: 'views/index.ejs', + templateParameters: { + config: appConfig + }, inject: true }), // copy custom static assets diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index 64f4562f..b6d5440b 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -52,21 +52,6 @@ const webpackConfig = merge(baseWebpackConfig, { ? { safe: true, map: { inline: false } } : { safe: true } }), - // generate dist index.html with correct asset hash for caching. - // you can customize output by editing /index.html - // see https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: config.build.index, - template: 'index.html', - inject: true, - minify: { - removeComments: true, - collapseWhitespace: true, - removeAttributeQuotes: true - // more options: - // https://github.com/kangax/html-minifier#options-quick-reference - }, - }), // keep module.id stable when vendor modules does not change new webpack.HashedModuleIdsPlugin(), // enable scope hoisting diff --git a/config/app.js b/config/app.js index 3d7ce88b..e82f15d5 100644 --- a/config/app.js +++ b/config/app.js @@ -1,5 +1,7 @@ // config/app.js module.exports = { + 'title': 'ZWave to MQTT', 'storeDir': 'store', + 'base': '/some/zwave', 'port': 8091 }; diff --git a/index.html b/views/index.ejs similarity index 54% rename from index.html rename to views/index.ejs index afba47b2..42538fbe 100644 --- a/index.html +++ b/views/index.ejs @@ -3,7 +3,8 @@ - Zwave To MQTT + <%= config.title %> + @@ -12,11 +13,11 @@ - - - - - + + + + + From bfb0827c24acff61971a7326f90ca1b067db6851 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 29 May 2020 18:41:15 -0500 Subject: [PATCH 03/33] Fix webpack; move default config --- build/webpack.dev.conf.js | 4 ++-- build/webpack.prod.conf.js | 1 - config/webConfig.js | 11 +++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 config/webConfig.js diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index f6879d98..fc7b3eed 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -2,7 +2,7 @@ const utils = require('./utils') const webpack = require('webpack') const config = require('../config') -const appConfig = require('../config/app'); +const appConfig = require('../config/webConfig'); const merge = require('webpack-merge') const path = require('path') const baseWebpackConfig = require('./webpack.base.conf') @@ -69,7 +69,7 @@ const devWebpackConfig = merge(baseWebpackConfig, { patterns: [ { from: path.resolve(__dirname, '../static'), - to: config.dev.assetsSubDirectory, + to: `${appConfig.base}/${config.dev.assetsSubDirectory}`, globOptions: { ignore: ['.*'] } diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index b6d5440b..79953c3f 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -6,7 +6,6 @@ const config = require('../config') const merge = require('webpack-merge') const baseWebpackConfig = require('./webpack.base.conf') const CopyWebpackPlugin = require('copy-webpack-plugin') -const HtmlWebpackPlugin = require('html-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') const TerserPlugin = require('terser-webpack-plugin') diff --git a/config/webConfig.js b/config/webConfig.js new file mode 100644 index 00000000..83ef2342 --- /dev/null +++ b/config/webConfig.js @@ -0,0 +1,11 @@ +const appConfig = require('./app'); + +const defaultConfig = { + base: '/', + title: 'ZWave To MQTT' +}; + +module.exports = { + ...defaultConfig, + ...appConfig +}; From 6f65b6ab0e53b8e489a632aa7b85a16ff41cff79 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 29 May 2020 18:41:32 -0500 Subject: [PATCH 04/33] Dynamically render index --- app.js | 4 +++- lib/renderIndex.js | 27 +++++++++++++++++++++++++++ views/index.ejs | 9 +++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 lib/renderIndex.js diff --git a/app.js b/app.js index ddafa6fb..4bccdb3e 100644 --- a/app.js +++ b/app.js @@ -14,9 +14,9 @@ var store = reqlib('config/store.js') var debug = reqlib('/lib/debug')('App') var history = require('connect-history-api-fallback') var utils = reqlib('/lib/utils.js') - var gw; //the gateway instance let io; +const renderIndex = reqlib('/lib/renderIndex') debug('Zwave2Mqtt version: ' + require('./package.json').version) debug('Application path:' + utils.getPath(true)) @@ -30,6 +30,8 @@ app.use(bodyParser.json({ limit: "50mb" })); app.use(bodyParser.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 })); app.use(cookieParser()); +app.get('/', renderIndex); + app.use('/', express.static(utils.joinPath(false, 'dist'))); app.use(cors()); diff --git a/lib/renderIndex.js b/lib/renderIndex.js new file mode 100644 index 00000000..ec78bd5f --- /dev/null +++ b/lib/renderIndex.js @@ -0,0 +1,27 @@ +const fs = require('fs') +const path = require('path') +var reqlib = require('app-root-path').require + +const webConfig = reqlib('/config/webConfig') + +function findFiles (folder, ext) { + const folderPath = path.join(__dirname, '..', 'dist', folder) + const folderFiles = fs.readdirSync(folderPath) + return folderFiles.filter(function (file) { + return path.extname(file).toLowerCase() === `.${ext.toLowerCase()}` + }).map(function (file) { + return path.join(folder, file) + }) +} + +const cssFiles = findFiles(path.join('static', 'css'), 'css') + +const jsFiles = findFiles(path.join('static', 'js'), 'js') + +module.exports = function (req, res) { + res.render('index.ejs', { + config: webConfig, + cssFiles, + jsFiles + }) +} diff --git a/views/index.ejs b/views/index.ejs index 42538fbe..689ee45e 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -20,9 +20,18 @@ + <% cssFiles %> + + <% for ( let css of cssFiles ){ %> + + <% } %>
+ + <% for ( let src of jsFiles ){ %> + + <% } %> From 88bc89c0a56e54253c2d20dafafee8ffcd03c36a Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 29 May 2020 20:14:08 -0500 Subject: [PATCH 05/33] Built production works --- build/webpack.base.conf.js | 9 ++++++--- config/app.js | 2 +- lib/renderIndex.js | 11 +++++++++-- src/App.vue | 7 ++++--- src/apis/ConfigApis.js | 15 ++++++--------- views/index.ejs | 13 ++++++++----- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index cd99abf1..b9ff2314 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -60,7 +60,8 @@ module.exports = { loader: 'url-loader', options: { limit: 10000, - name: utils.assetsPath('img/[name].[hash:7].[ext]') + name: utils.assetsPath('img/[name].[hash:7].[ext]'), + publicPath: '..' } }, { @@ -68,7 +69,8 @@ module.exports = { loader: 'url-loader', options: { limit: 10000, - name: utils.assetsPath('media/[name].[hash:7].[ext]') + name: utils.assetsPath('media/[name].[hash:7].[ext]'), + publicPath: '.' } }, { @@ -76,7 +78,8 @@ module.exports = { loader: 'url-loader', options: { limit: 10000, - name: utils.assetsPath('fonts/[name].[hash:7].[ext]') + name: utils.assetsPath('fonts/[name].[hash:7].[ext]'), + publicPath: '../..' } }, { diff --git a/config/app.js b/config/app.js index e82f15d5..f6b68454 100644 --- a/config/app.js +++ b/config/app.js @@ -2,6 +2,6 @@ module.exports = { 'title': 'ZWave to MQTT', 'storeDir': 'store', - 'base': '/some/zwave', + 'base': '/', 'port': 8091 }; diff --git a/lib/renderIndex.js b/lib/renderIndex.js index ec78bd5f..c12269c5 100644 --- a/lib/renderIndex.js +++ b/lib/renderIndex.js @@ -15,12 +15,19 @@ function findFiles (folder, ext) { } const cssFiles = findFiles(path.join('static', 'css'), 'css') - const jsFiles = findFiles(path.join('static', 'js'), 'js') +function basePath (config, headers) { + return headers['x-external-path'] || config.base +} + module.exports = function (req, res) { + console.log('Request: ', req.headers) res.render('index.ejs', { - config: webConfig, + config: { + ...webConfig, + base: basePath(webConfig, req.headers) + }, cssFiles, jsFiles }) diff --git a/src/App.vue b/src/App.vue index df084eb9..6e8329db 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,7 +4,7 @@ - + {{"ZWave2MQTT v" + version}} @@ -193,7 +193,8 @@ export default { title: '', snackbar: false, snackbarText: '', - dark: false + dark: false, + baseURI: document.baseURI } }, watch: { @@ -212,7 +213,7 @@ export default { var self = this - this.socket = io(ConfigApis.getSocketIP()) + this.socket = io(ConfigApis.getSocketIP(), { path: ConfigApis.getSocketPath() }) this.socket.on('connect', () => { self.updateStatus('Connected', 'green') diff --git a/src/apis/ConfigApis.js b/src/apis/ConfigApis.js index fbfc9efd..4232ea27 100644 --- a/src/apis/ConfigApis.js +++ b/src/apis/ConfigApis.js @@ -1,20 +1,17 @@ import axios from 'axios' - import { loadProgressBar } from 'axios-progress-bar' -if (process.env.NODE_ENV === 'development') { - axios.defaults.socketUrl = location.protocol + '//' + location.hostname + ':' + process.env.PORT - axios.defaults.baseURL = axios.defaults.socketUrl + '/api' -} else { - var port = parseInt(window.location.port) || (window.location.protocol === 'https:' ? 443 : 80) - axios.defaults.socketUrl = location.protocol + '//' + location.hostname + ':' + port - axios.defaults.baseURL = '/api' -} +axios.defaults.socketUrl = document.baseURI +axios.defaults.baseURL = axios.defaults.socketUrl + '/api' loadProgressBar() export default { getSocketIP () { return axios.defaults.socketUrl }, + getSocketPath () { + const innerPath = document.baseURI.split('/').splice(3).join('/') + return `/${innerPath}/socket.io`.replace('//', '/') + }, getConfig () { return axios.get('/settings') .then(response => { diff --git a/views/index.ejs b/views/index.ejs index 689ee45e..575bb09a 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -20,17 +20,20 @@ - <% cssFiles %> - <% for ( let css of cssFiles ){ %> - + <% if (typeof cssFiles !== 'undefined') { %> + <% for ( let css of cssFiles ){ %> + + <% } %> <% } %>
- <% for ( let src of jsFiles ){ %> - + <% if (typeof jsFiles !== 'undefined') { %> + <% for ( let src of jsFiles ){ %> + + <% } %> <% } %> From c5219fbd10325749f51ad31201fa11b4e1235b05 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 29 May 2020 20:50:47 -0500 Subject: [PATCH 06/33] Mostly working --- lib/renderIndex.js | 3 +-- src/App.vue | 6 ++++-- src/apis/ConfigApis.js | 16 +++++++++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/renderIndex.js b/lib/renderIndex.js index c12269c5..458edf2f 100644 --- a/lib/renderIndex.js +++ b/lib/renderIndex.js @@ -18,11 +18,10 @@ const cssFiles = findFiles(path.join('static', 'css'), 'css') const jsFiles = findFiles(path.join('static', 'js'), 'js') function basePath (config, headers) { - return headers['x-external-path'] || config.base + return (headers['x-external-path'] || config.base).replace(/\/$/, '') } module.exports = function (req, res) { - console.log('Request: ', req.headers) res.render('index.ejs', { config: { ...webConfig, diff --git a/src/App.vue b/src/App.vue index 6e8329db..7235f033 100644 --- a/src/App.vue +++ b/src/App.vue @@ -194,7 +194,7 @@ export default { snackbar: false, snackbarText: '', dark: false, - baseURI: document.baseURI + baseURI: ConfigApis.getBasePath() } }, watch: { @@ -213,7 +213,9 @@ export default { var self = this - this.socket = io(ConfigApis.getSocketIP(), { path: ConfigApis.getSocketPath() }) + this.socket = io(ConfigApis.getSocketIP(), { + path: ConfigApis.getSocketPath() + }) this.socket.on('connect', () => { self.updateStatus('Connected', 'green') diff --git a/src/apis/ConfigApis.js b/src/apis/ConfigApis.js index 4232ea27..a18c874c 100644 --- a/src/apis/ConfigApis.js +++ b/src/apis/ConfigApis.js @@ -1,16 +1,26 @@ import axios from 'axios' import { loadProgressBar } from 'axios-progress-bar' -axios.defaults.socketUrl = document.baseURI +function getBasePath () { + return document.baseURI.replace(/\/$/, '') +} + +axios.defaults.socketUrl = getBasePath() axios.defaults.baseURL = axios.defaults.socketUrl + '/api' loadProgressBar() export default { - getSocketIP () { return axios.defaults.socketUrl }, + getBasePath () { + return getBasePath() + }, + getSocketIP () { + return getBasePath() + }, getSocketPath () { const innerPath = document.baseURI.split('/').splice(3).join('/') - return `/${innerPath}/socket.io`.replace('//', '/') + const socketPath = `/${innerPath}/socket.io`.replace('//', '/') + return socketPath === '/socket.io' ? undefined : socketPath }, getConfig () { return axios.get('/settings') From c06011ca9854cf9d2a93b9cf4c8b39d224a8a3c9 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Sat, 30 May 2020 08:28:02 -0500 Subject: [PATCH 07/33] Add some documentation --- docs/subpath.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/subpath.md diff --git a/docs/subpath.md b/docs/subpath.md new file mode 100644 index 00000000..7bc67f69 --- /dev/null +++ b/docs/subpath.md @@ -0,0 +1,43 @@ +# ZWave To MQTT Behind a Reverse Proxy + +There are two ways to enable ZWave To MQTT to sit behing a proxy that uses +subpaths to serve the pages and services. + +You can use a header to signal where the external path is or you can configure +the base path. In both cases this are dynamic configurations, so you can deploy +without having to build again the frontend. + +## Using an HTTP header + +You can pass the external path by setting the `X-External-Path` header, for example +suppose you had the following `nginx` configuration: + +```nginx +server { + + listen 9000 default_server; + listen [::]:9000 default_server; + + location /some/deep/map/ { + proxy_pass http://127.0.0.1:8091/; + proxy_set_header X-External-Path /some/deep/map; + } +} +``` + +This will tell the application to serve the application and relevant elements under +`/some/deep/map`. + +In case you are using the ingress of Home Assistant you will want to +pick up the `X-Ingress-Path;` and map it, something along +these lines: + +```nginx + proxy_set_header X-External-Path $http_x_ingress_path; +``` + +## Using the configuration + +You can simply change the `config/app.js` and set `base` to whatever is +the subpath you will be serving this from. + From ffc7ae8918dbc22368e8dc570b61db1c4c10ea03 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Sat, 30 May 2020 08:45:47 -0500 Subject: [PATCH 08/33] Fix up documentation --- docs/subpath.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/subpath.md b/docs/subpath.md index 7bc67f69..a9df9ae3 100644 --- a/docs/subpath.md +++ b/docs/subpath.md @@ -12,16 +12,15 @@ without having to build again the frontend. You can pass the external path by setting the `X-External-Path` header, for example suppose you had the following `nginx` configuration: -```nginx +```text server { + listen 9000 default_server; + listen [::]:9000 default_server; - listen 9000 default_server; - listen [::]:9000 default_server; - - location /some/deep/map/ { - proxy_pass http://127.0.0.1:8091/; - proxy_set_header X-External-Path /some/deep/map; - } + location /some/deep/map/ { + proxy_pass http://127.0.0.1:8091/; + proxy_set_header X-External-Path /some/deep/map; + } } ``` @@ -32,8 +31,8 @@ In case you are using the ingress of Home Assistant you will want to pick up the `X-Ingress-Path;` and map it, something along these lines: -```nginx - proxy_set_header X-External-Path $http_x_ingress_path; +```text + proxy_set_header X-External-Path $http_x_ingress_path; ``` ## Using the configuration @@ -41,3 +40,14 @@ these lines: You can simply change the `config/app.js` and set `base` to whatever is the subpath you will be serving this from. +As an example, if your proxy is placing the app behind `/zwave/` your configuration +would look like: + +```javascript +module.exports = { + 'title': 'ZWave to MQTT', + 'storeDir': 'store', + 'base': '/zwave/', + 'port': 8091 +}; +``` From 6fc834c7eab1b4c24f8632a7b1c716a1f047eb91 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Sat, 30 May 2020 08:52:20 -0500 Subject: [PATCH 09/33] Link to subpath docs from main README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 604f4fab..13ee80b1 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,11 @@ kubectl apply -k https://raw.githubusercontent.com/openzwave/zwave2mqtt/master/k 4. Open the browser +### Reverse Proxy Setup + +If you need to setup ZWave To MQTT behind a reverse proxy that needs a *subpath* to +work, take a look at [this](docs/subpath.md). + ## :nerd_face: Development Developers who wants to debug the application have to open 2 terminals. @@ -413,6 +418,7 @@ Zwave2Mqtt to resend the cached values when Home Assistant restarts. Zwave2Mqtt try to do its best to guess how to map devices from Zwave to HASS. At the moment it try to guess the device to generate based on zwave values command classes, index and units of the value. When the discovered device doesn't fit your needs you can you can set custom a `device_class` to values using Gateway value table. + ### Components management To see the components that have been discovered by Zwave2Mqtt go to Control Panel UI, select a Node from the Nodes table then select the Node tab from tabs menu at the bottom of Nodes table. Now at the Bottom of the page, after Node values section you can find a new section called `Home Assistant - Devices`. Here you will see a table with all devices created for the selected node. From efaf968b796adfa9bbb6062ff60c21e42642b5f6 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Sat, 30 May 2020 11:08:55 -0500 Subject: [PATCH 10/33] Add unit tests --- lib/renderIndex.js | 8 +-- test/lib/renderIndex.test.js | 96 ++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 test/lib/renderIndex.test.js diff --git a/lib/renderIndex.js b/lib/renderIndex.js index 458edf2f..973d3caa 100644 --- a/lib/renderIndex.js +++ b/lib/renderIndex.js @@ -1,6 +1,6 @@ const fs = require('fs') const path = require('path') -var reqlib = require('app-root-path').require +const reqlib = require('app-root-path').require const webConfig = reqlib('/config/webConfig') @@ -14,14 +14,16 @@ function findFiles (folder, ext) { }) } -const cssFiles = findFiles(path.join('static', 'css'), 'css') -const jsFiles = findFiles(path.join('static', 'js'), 'js') +let cssFiles +let jsFiles function basePath (config, headers) { return (headers['x-external-path'] || config.base).replace(/\/$/, '') } module.exports = function (req, res) { + cssFiles = cssFiles || findFiles(path.join('static', 'css'), 'css') + jsFiles = jsFiles || findFiles(path.join('static', 'js'), 'js') res.render('index.ejs', { config: { ...webConfig, diff --git a/test/lib/renderIndex.test.js b/test/lib/renderIndex.test.js new file mode 100644 index 00000000..5d7035e4 --- /dev/null +++ b/test/lib/renderIndex.test.js @@ -0,0 +1,96 @@ +const chai = require('chai') +const sinon = require('sinon') +const rewire = require('rewire') +const fs = require('fs') +const path = require('path') + +const cssFolder = path.join(__dirname, '..', '..', 'dist', 'static', 'css') +const jsFolder = path.join(__dirname, '..', '..', 'dist', 'static', 'js') + +chai.use(require('sinon-chai')) +chai.should() + +let lastTpl +let lastOptions + +const mockResponse = { + render: (tpl, options) => { + lastTpl = tpl + lastOptions = options + } +} + +describe('#renderIndex', () => { + describe('Processing configuration', () => { + let renderIndex + + beforeEach(() => { + renderIndex = rewire('../../lib/renderIndex') + renderIndex.__set__('webConfig', { + base: '/configured/path' + }) + }) + + it('uses the base from the `X-External-Path` header', () => { + renderIndex({ + headers: { + 'x-external-path': '/test/base' + } + }, mockResponse) + lastOptions.config.base.should.equal('/test/base') + }) + + it('uses configured value if no header is present', () => { + renderIndex({ + headers: {} + }, mockResponse) + lastOptions.config.base.should.equal('/configured/path') + }) + }) + + describe('Processing static files', () => { + let mockedReaddir + let renderIndex + + beforeEach(() => { + renderIndex = rewire('../../lib/renderIndex') + mockedReaddir = sinon.stub(fs, 'readdirSync') + }) + + afterEach(() => { + mockedReaddir.restore() + }) + + it('When no dist files present it will have empty css and js files', () => { + mockedReaddir.returns([]) + renderIndex({ + headers: {} + }, mockResponse) + lastTpl.should.equal('index.ejs') + lastOptions.cssFiles.should.eql([]) + lastOptions.jsFiles.should.eql([]) + }) + + it('When dist files present will only return the ones with the correct extensions', () => { + console.log(cssFolder) + mockedReaddir + .withArgs(cssFolder) + .returns([ + 'valid-css.css', + 'invalid-css.scss' + ]) + mockedReaddir + .withArgs(jsFolder) + .returns([ + 'valid-js.js', + 'invalid-js.map' + ]) + renderIndex({ + headers: {} + }, mockResponse) + lastTpl.should.equal('index.ejs') + lastOptions.cssFiles.should.eql(['static/css/valid-css.css']) + lastOptions.jsFiles.should.eql(['static/js/valid-js.js']) + }) + }) +}) From c738c5f9dc311a6362c1293236bc0c77f70505e1 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Sat, 30 May 2020 12:06:43 -0500 Subject: [PATCH 11/33] Add missing (?) ejs package --- package-lock.json | 64 +++++++++++++++++++++++++++++++++++++---------- package.json | 1 + 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 21e353c3..3b195537 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4179,7 +4179,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -6496,7 +6495,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -6504,8 +6502,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { "version": "1.5.3", @@ -8158,10 +8155,12 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "ejs": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", - "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", - "dev": true + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.3.tgz", + "integrity": "sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg==", + "requires": { + "jake": "^10.6.1" + } }, "electron-to-chromium": { "version": "1.3.441", @@ -8439,8 +8438,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { "version": "6.8.0", @@ -9734,6 +9732,14 @@ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, + "filelist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz", + "integrity": "sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ==", + "requires": { + "minimatch": "^3.0.4" + } + }, "filesize": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", @@ -10543,8 +10549,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.1", @@ -11730,6 +11735,34 @@ "istanbul-lib-report": "^3.0.0" } }, + "jake": { + "version": "10.7.1", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.7.1.tgz", + "integrity": "sha512-FUkLZXms1LSTQop5EJBdXVzbM0q6yYWMM4vo/TiLQeHJ4UMJVO8DBTZFiAgMBJctin9q92xnr2vdH7Wrpn7tTQ==", + "requires": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, "jest-worker": { "version": "26.0.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.0.0.tgz", @@ -19223,7 +19256,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -20813,6 +20845,12 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "dev": true } } }, diff --git a/package.json b/package.json index d3687246..ba6f4a32 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "cookie-parser": "^1.4.5", "cors": "^2.8.5", "debug": "^4.1.1", + "ejs": "^3.1.3", "express": "^4.17.1", "jsonfile": "^6.0.1", "morgan": "~1.10.0", From 6f545690b82dbfa3aef824f387bc2e117df5ee2a Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Mon, 1 Jun 2020 07:34:40 -0500 Subject: [PATCH 12/33] TIL: Socket Namespaces --- src/App.vue | 2 +- src/apis/ConfigApis.js | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/App.vue b/src/App.vue index 7235f033..c58f3a16 100644 --- a/src/App.vue +++ b/src/App.vue @@ -213,7 +213,7 @@ export default { var self = this - this.socket = io(ConfigApis.getSocketIP(), { + this.socket = this.socket = io('/', { path: ConfigApis.getSocketPath() }) diff --git a/src/apis/ConfigApis.js b/src/apis/ConfigApis.js index a18c874c..7d5ff80b 100644 --- a/src/apis/ConfigApis.js +++ b/src/apis/ConfigApis.js @@ -14,9 +14,6 @@ export default { getBasePath () { return getBasePath() }, - getSocketIP () { - return getBasePath() - }, getSocketPath () { const innerPath = document.baseURI.split('/').splice(3).join('/') const socketPath = `/${innerPath}/socket.io`.replace('//', '/') From 86cc3230dfa94ae674f6e1fc2824975f19290eee Mon Sep 17 00:00:00 2001 From: fabio-torchetti <53441171+fabio-torchetti@users.noreply.github.com> Date: Wed, 3 Jun 2020 08:00:57 -0500 Subject: [PATCH 13/33] Update docs/subpath.md Co-authored-by: Chris Nesbitt-Smith --- docs/subpath.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/subpath.md b/docs/subpath.md index a9df9ae3..ce59a1bf 100644 --- a/docs/subpath.md +++ b/docs/subpath.md @@ -4,7 +4,7 @@ There are two ways to enable ZWave To MQTT to sit behing a proxy that uses subpaths to serve the pages and services. You can use a header to signal where the external path is or you can configure -the base path. In both cases this are dynamic configurations, so you can deploy +the base path. In both cases these are dynamic configurations, so you can deploy without having to build again the frontend. ## Using an HTTP header From 881aace1e94c006a3692de0eb28a88bdbb9852bb Mon Sep 17 00:00:00 2001 From: fabio-torchetti <53441171+fabio-torchetti@users.noreply.github.com> Date: Wed, 3 Jun 2020 08:02:50 -0500 Subject: [PATCH 14/33] Update src/apis/ConfigApis.js Co-authored-by: Chris Nesbitt-Smith --- src/apis/ConfigApis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/ConfigApis.js b/src/apis/ConfigApis.js index 7d5ff80b..dfda24f8 100644 --- a/src/apis/ConfigApis.js +++ b/src/apis/ConfigApis.js @@ -6,7 +6,7 @@ function getBasePath () { } axios.defaults.socketUrl = getBasePath() -axios.defaults.baseURL = axios.defaults.socketUrl + '/api' +axios.defaults.baseURL = `${axios.defaults.socketUrl}/api` loadProgressBar() From 9ae6c8a2fc16eea1ab4a4a73eff46fa1b9945b02 Mon Sep 17 00:00:00 2001 From: fabio-torchetti <53441171+fabio-torchetti@users.noreply.github.com> Date: Wed, 3 Jun 2020 08:03:12 -0500 Subject: [PATCH 15/33] Update docs/subpath.md Co-authored-by: Chris Nesbitt-Smith --- docs/subpath.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/subpath.md b/docs/subpath.md index ce59a1bf..1e257150 100644 --- a/docs/subpath.md +++ b/docs/subpath.md @@ -27,7 +27,7 @@ server { This will tell the application to serve the application and relevant elements under `/some/deep/map`. -In case you are using the ingress of Home Assistant you will want to +In case you are using the [ingress of Home Assistant](https://www.home-assistant.io/blog/2019/04/15/hassio-ingress/) you will want to pick up the `X-Ingress-Path;` and map it, something along these lines: From cbcc7f384f636f4dcfbceeae265e2d008b531fac Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 08:17:13 -0500 Subject: [PATCH 16/33] Add reverse proxy setup to Readme TOC --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 13ee80b1..ec19d818 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ After a [discussion](https://github.com/OpenZWave/Zwave2Mqtt/issues/201) with Op - [DOCKER :tada: way](#docker-tada-way) - [Kubernetes way](#kubernetes-way) - [NodeJS or PKG version](#nodejs-or-pkg-version) + - [Reverse Proxy Setup](#reverse-proxy-setup) - [:nerd_face: Development](#nerdface-development) - [:wrench: Usage](#wrench-usage) - [Zwave](#zwave) From b2cf1a309dc6a2858b80595920770a86c235cb30 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 08:18:07 -0500 Subject: [PATCH 17/33] Remove trailing white line --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ec19d818..68ff0a14 100644 --- a/README.md +++ b/README.md @@ -419,7 +419,6 @@ Zwave2Mqtt to resend the cached values when Home Assistant restarts. Zwave2Mqtt try to do its best to guess how to map devices from Zwave to HASS. At the moment it try to guess the device to generate based on zwave values command classes, index and units of the value. When the discovered device doesn't fit your needs you can you can set custom a `device_class` to values using Gateway value table. - ### Components management To see the components that have been discovered by Zwave2Mqtt go to Control Panel UI, select a Node from the Nodes table then select the Node tab from tabs menu at the bottom of Nodes table. Now at the Bottom of the page, after Node values section you can find a new section called `Home Assistant - Devices`. Here you will see a table with all devices created for the selected node. From b6fb1e5f726faf2525eca35f50c28472920f1844 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 08:18:51 -0500 Subject: [PATCH 18/33] Remove trailing semicolon from webpack config --- build/webpack.dev.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index fc7b3eed..298c94a3 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -2,7 +2,7 @@ const utils = require('./utils') const webpack = require('webpack') const config = require('../config') -const appConfig = require('../config/webConfig'); +const appConfig = require('../config/webConfig') const merge = require('webpack-merge') const path = require('path') const baseWebpackConfig = require('./webpack.base.conf') From cb56e4c88902f9e6837041838fbb89305dd4c8bc Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 08:20:29 -0500 Subject: [PATCH 19/33] Move require to the requirements block --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 4bccdb3e..f8b2266b 100644 --- a/app.js +++ b/app.js @@ -14,9 +14,9 @@ var store = reqlib('config/store.js') var debug = reqlib('/lib/debug')('App') var history = require('connect-history-api-fallback') var utils = reqlib('/lib/utils.js') +const renderIndex = reqlib('/lib/renderIndex') var gw; //the gateway instance let io; -const renderIndex = reqlib('/lib/renderIndex') debug('Zwave2Mqtt version: ' + require('./package.json').version) debug('Application path:' + utils.getPath(true)) From 6cf94e0653f913870185539e3919de72317578ff Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 08:21:16 -0500 Subject: [PATCH 20/33] Fix MD language for NGinx --- docs/subpath.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/subpath.md b/docs/subpath.md index 1e257150..057d4116 100644 --- a/docs/subpath.md +++ b/docs/subpath.md @@ -12,7 +12,7 @@ without having to build again the frontend. You can pass the external path by setting the `X-External-Path` header, for example suppose you had the following `nginx` configuration: -```text +```nginx server { listen 9000 default_server; listen [::]:9000 default_server; @@ -31,7 +31,7 @@ In case you are using the [ingress of Home Assistant](https://www.home-assistant pick up the `X-Ingress-Path;` and map it, something along these lines: -```text +```nginx proxy_set_header X-External-Path $http_x_ingress_path; ``` From 529ab95fb516498de3085d7ca90ff7bfcf985117 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 08:22:44 -0500 Subject: [PATCH 21/33] Remove `favicons` comment --- views/index.ejs | 1 - 1 file changed, 1 deletion(-) diff --git a/views/index.ejs b/views/index.ejs index 575bb09a..ad8fc57c 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -5,7 +5,6 @@ <%= config.title %> - From 95e1fa2c06f3e272caa76f188c61cf765a5be26f Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 12:14:03 -0500 Subject: [PATCH 22/33] Add 'proxyquire' as a dev dependency --- package-lock.json | 33 +++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 34 insertions(+) diff --git a/package-lock.json b/package-lock.json index 3b195537..273863b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9746,6 +9746,16 @@ "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", "dev": true }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -11521,6 +11531,12 @@ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -12745,6 +12761,12 @@ } } }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -16360,6 +16382,17 @@ "ipaddr.js": "1.9.1" } }, + "proxyquire": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", + "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.1", + "resolve": "^1.11.1" + } + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", diff --git a/package.json b/package.json index ba6f4a32..6fbe02c9 100644 --- a/package.json +++ b/package.json @@ -169,6 +169,7 @@ "postcss-import": "^12.0.1", "postcss-loader": "^3.0.0", "postcss-url": "^8.0.0", + "proxyquire": "^2.1.3", "release-it": "^13.6.1", "rewire": "^5.0.0", "rimraf": "^3.0.2", From d75b8a5bc2f595ded10b9ee4600658be97701b16 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 12:14:41 -0500 Subject: [PATCH 23/33] Ensure base path has always a trailing slash --- config/app.js | 2 +- config/webConfig.js | 2 ++ test/config/webConfig.test.js | 47 +++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 test/config/webConfig.test.js diff --git a/config/app.js b/config/app.js index f6b68454..38328503 100644 --- a/config/app.js +++ b/config/app.js @@ -1,6 +1,6 @@ // config/app.js module.exports = { - 'title': 'ZWave to MQTT', + 'title': 'ZWave To MQTT', 'storeDir': 'store', 'base': '/', 'port': 8091 diff --git a/config/webConfig.js b/config/webConfig.js index 83ef2342..87af02de 100644 --- a/config/webConfig.js +++ b/config/webConfig.js @@ -1,5 +1,7 @@ const appConfig = require('./app'); +appConfig.base = appConfig.base && appConfig.base.replace(/\/?$/, '/') + const defaultConfig = { base: '/', title: 'ZWave To MQTT' diff --git a/test/config/webConfig.test.js b/test/config/webConfig.test.js new file mode 100644 index 00000000..3c52c3ba --- /dev/null +++ b/test/config/webConfig.test.js @@ -0,0 +1,47 @@ +const chai = require('chai') +const proxyquire = require('proxyquire') + +chai.use(require('sinon-chai')) +chai.should() + +describe('#webConfig', () => { + const webConfig = proxyquire('../../config/webConfig', { + './app': {} + }) + + describe('Uses defaults if nothing specified', () => { + it('uses "/" as the default base', () => { + webConfig.base.should.equal('/') + }) + it('uses "ZWave To MQTT" as the default title', () => { + webConfig.title.should.equal('ZWave To MQTT') + }) + }) + describe('Uses config values when pecified', () => { + const webConfig = proxyquire('../../config/webConfig', { + './app': { + base: '/sub/path/', + title: 'Custom Title' + } + }) + + it('uses "/sub/path/" as the custom base', () => { + webConfig.base.should.equal('/sub/path/') + }) + + it('uses "Custom Title" as the custom title', () => { + webConfig.title.should.equal('Custom Title') + }) + }) + + describe('Path normalization', () => { + const webConfig = proxyquire('../../config/webConfig', { + './app': { + base: '/sub/path' + } + }) + it('Ensures base paths ends with a slash', () => { + webConfig.base.should.equal('/sub/path/') + }) + }) +}) From 300a8cd460ccbfa1c076d7c9598cfc352b45b6b2 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 13:43:04 -0500 Subject: [PATCH 24/33] Fix development assets layout --- build/webpack.base.conf.js | 6 ++---- build/webpack.dev.conf.js | 8 ++------ lib/renderIndex.js | 2 +- test/lib/renderIndex.test.js | 4 ++-- views/index.ejs | 14 +++++++------- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index b9ff2314..660a18c5 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -60,8 +60,7 @@ module.exports = { loader: 'url-loader', options: { limit: 10000, - name: utils.assetsPath('img/[name].[hash:7].[ext]'), - publicPath: '..' + name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { @@ -69,8 +68,7 @@ module.exports = { loader: 'url-loader', options: { limit: 10000, - name: utils.assetsPath('media/[name].[hash:7].[ext]'), - publicPath: '.' + name: utils.assetsPath('media/[name].[hash:7].[ext]') } }, { diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index 298c94a3..5eb13de9 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -25,11 +25,7 @@ const devWebpackConfig = merge(baseWebpackConfig, { // these devServer options should be customized in /config/index.js devServer: { clientLogLevel: 'warning', - historyApiFallback: { - rewrites: [ - { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, - ], - }, + historyApiFallback: true, hot: true, contentBase: false, // since we use CopyWebpackPlugin. compress: true, @@ -69,7 +65,7 @@ const devWebpackConfig = merge(baseWebpackConfig, { patterns: [ { from: path.resolve(__dirname, '../static'), - to: `${appConfig.base}/${config.dev.assetsSubDirectory}`, + to: config.dev.assetsSubDirectory, globOptions: { ignore: ['.*'] } diff --git a/lib/renderIndex.js b/lib/renderIndex.js index 973d3caa..a79d8f9c 100644 --- a/lib/renderIndex.js +++ b/lib/renderIndex.js @@ -18,7 +18,7 @@ let cssFiles let jsFiles function basePath (config, headers) { - return (headers['x-external-path'] || config.base).replace(/\/$/, '') + return (headers['x-external-path'] || config.base).replace(/\/?$/, '/') } module.exports = function (req, res) { diff --git a/test/lib/renderIndex.test.js b/test/lib/renderIndex.test.js index 5d7035e4..5e931368 100644 --- a/test/lib/renderIndex.test.js +++ b/test/lib/renderIndex.test.js @@ -37,14 +37,14 @@ describe('#renderIndex', () => { 'x-external-path': '/test/base' } }, mockResponse) - lastOptions.config.base.should.equal('/test/base') + lastOptions.config.base.should.equal('/test/base/') }) it('uses configured value if no header is present', () => { renderIndex({ headers: {} }, mockResponse) - lastOptions.config.base.should.equal('/configured/path') + lastOptions.config.base.should.equal('/configured/path/') }) }) diff --git a/views/index.ejs b/views/index.ejs index ad8fc57c..b6b5dc5f 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -12,17 +12,17 @@ - - - - - + + + + + <% if (typeof cssFiles !== 'undefined') { %> <% for ( let css of cssFiles ){ %> - + <% } %> <% } %> @@ -31,7 +31,7 @@ <% if (typeof jsFiles !== 'undefined') { %> <% for ( let src of jsFiles ){ %> - + <% } %> <% } %> From 066c2284f061b8df1465cf79538cb61202d7cd0f Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 13:43:23 -0500 Subject: [PATCH 25/33] Add full practical example of reverse proxy --- docs/subpath.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/subpath.md b/docs/subpath.md index 057d4116..deebccff 100644 --- a/docs/subpath.md +++ b/docs/subpath.md @@ -13,14 +13,22 @@ You can pass the external path by setting the `X-External-Path` header, for exam suppose you had the following `nginx` configuration: ```nginx -server { - listen 9000 default_server; - listen [::]:9000 default_server; - - location /some/deep/map/ { - proxy_pass http://127.0.0.1:8091/; - proxy_set_header X-External-Path /some/deep/map; - } +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 9000 default_server; + listen [::]:9000 default_server; + + location /hassio/ingress/ { + proxy_pass http://localhost:8091/; + proxy_set_header X-External-Path /hassio/ingress; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + } } ``` From 6b1a593fd980aa70649b792f63f36df617f0be92 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Wed, 3 Jun 2020 14:08:00 -0500 Subject: [PATCH 26/33] Proxy to nodejs service for development of UI --- config/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/config/index.js b/config/index.js index 7d6e710f..b0893ea5 100644 --- a/config/index.js +++ b/config/index.js @@ -10,7 +10,12 @@ module.exports = { // Paths assetsSubDirectory: 'static', assetsPublicPath: '/', - proxyTable: {}, + proxyTable: { + '/socket.io': { + target: 'ws://localhost:8091', + ws: true + }, + }, // Various Dev Server settings host: 'localhost', // can be overwritten by process.env.HOST From 776170321e56d6530145332c983961452d3e8112 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Thu, 4 Jun 2020 17:17:37 -0500 Subject: [PATCH 27/33] Fix missing mapping --- app.js | 4 ++-- config/index.js | 2 ++ docs/subpath.md | 40 ++++++++++++++++++++-------------------- package.json | 2 +- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app.js b/app.js index f8b2266b..4fd42f69 100644 --- a/app.js +++ b/app.js @@ -62,7 +62,7 @@ app.startSocket = function (server) { io.on('connection', function (socket) { debug("New connection", socket.id); - + socket.on('INITED', function () { if(gw.zwave) socket.emit('INIT', { nodes: gw.zwave.nodes, info: gw.zwave.ozwConfig, error: gw.zwave.error, cntStatus: gw.zwave.cntStatus }) @@ -147,7 +147,7 @@ app.get('/health/:client', async function (req, res) { status = gw && gw[client] ? gw[client].getStatus().status : false } - res.status(status ? 200 : 500).send(status ? 'Ok' : 'Error') + res.status(status ? 200 : 500).send(status ? 'Ok' : 'Error') }) diff --git a/config/index.js b/config/index.js index b0893ea5..37400c7b 100644 --- a/config/index.js +++ b/config/index.js @@ -15,6 +15,8 @@ module.exports = { target: 'ws://localhost:8091', ws: true }, + '/health': 'http://localhost:8091', + '/api': 'http://localhost:8091' }, // Various Dev Server settings diff --git a/docs/subpath.md b/docs/subpath.md index deebccff..df7d702e 100644 --- a/docs/subpath.md +++ b/docs/subpath.md @@ -1,7 +1,7 @@ # ZWave To MQTT Behind a Reverse Proxy There are two ways to enable ZWave To MQTT to sit behing a proxy that uses -subpaths to serve the pages and services. +subpaths to serve the pages and services. You can use a header to signal where the external path is or you can configure the base path. In both cases these are dynamic configurations, so you can deploy @@ -13,21 +13,21 @@ You can pass the external path by setting the `X-External-Path` header, for exam suppose you had the following `nginx` configuration: ```nginx -map $http_upgrade $connection_upgrade { - default upgrade; - '' close; -} - -server { - listen 9000 default_server; - listen [::]:9000 default_server; - - location /hassio/ingress/ { - proxy_pass http://localhost:8091/; - proxy_set_header X-External-Path /hassio/ingress; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 9000 default_server; + listen [::]:9000 default_server; + + location /hassio/ingress/ { + proxy_pass http://localhost:8091/; + proxy_set_header X-External-Path /hassio/ingress; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; } } ``` @@ -53,9 +53,9 @@ would look like: ```javascript module.exports = { - 'title': 'ZWave to MQTT', - 'storeDir': 'store', - 'base': '/zwave/', - 'port': 8091 + 'title': 'ZWave to MQTT', + 'storeDir': 'store', + 'base': '/zwave/', + 'port': 8091 }; ``` diff --git a/package.json b/package.json index 5563626b..3b71c341 100644 --- a/package.json +++ b/package.json @@ -205,4 +205,4 @@ "last 2 versions", "not ie <= 8" ] -} \ No newline at end of file +} From a957e1729bbfd5d34470fa42ca41abde3ac366f3 Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 5 Jun 2020 07:43:40 -0500 Subject: [PATCH 28/33] Linter fixes -- need to start auto running it! --- .vscode/settings.json | 5 +++- README.md | 2 +- app.js | 8 +++--- config/app.js | 10 ++++---- config/index.js | 6 ++--- config/webConfig.js | 14 +++++----- docs/subpath.md | 10 ++++---- lib/renderIndex.js | 12 +++++---- src/App.vue | 12 ++++++--- src/apis/ConfigApis.js | 5 +++- test/lib/renderIndex.test.js | 50 ++++++++++++++++++++---------------- 11 files changed, 77 insertions(+), 57 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e4b18547..db3370ae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,8 @@ "eslint.format.enable": true, "editor.defaultFormatter": "numso.prettier-standard-vscode", "eslint.lintTask.enable": true, - "wallaby.startAutomatically": true + "wallaby.startAutomatically": true, + "[vue]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + } } diff --git a/README.md b/README.md index ab67ea99..e5ee3e4b 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ kubectl apply -k https://raw.githubusercontent.com/openzwave/zwave2mqtt/master/k ### Reverse Proxy Setup -If you need to setup ZWave To MQTT behind a reverse proxy that needs a *subpath* to +If you need to setup ZWave To MQTT behind a reverse proxy that needs a _subpath_ to work, take a look at [this](docs/subpath.md). ## :nerd_face: Development diff --git a/app.js b/app.js index 5cee02d3..46ae501f 100644 --- a/app.js +++ b/app.js @@ -15,8 +15,8 @@ var debug = reqlib('/lib/debug')('App') var history = require('connect-history-api-fallback') var utils = reqlib('/lib/utils.js') const renderIndex = reqlib('/lib/renderIndex') -var gw; //the gateway instance -let io; +var gw //the gateway instance +let io debug('Zwave2Mqtt version: ' + require('./package.json').version) debug('Application path:' + utils.getPath(true)) @@ -36,9 +36,9 @@ app.use( ) app.use(cookieParser()) -app.get('/', renderIndex); +app.get('/', renderIndex) -app.use('/', express.static(utils.joinPath(false, 'dist'))); +app.use('/', express.static(utils.joinPath(false, 'dist'))) app.use(cors()) diff --git a/config/app.js b/config/app.js index 98c9fa87..9a0e84a5 100644 --- a/config/app.js +++ b/config/app.js @@ -1,7 +1,7 @@ // config/app.js module.exports = { - title: 'ZWave To MQTT', - storeDir: 'store', - base: '/', - port: 8091 -}; + title: 'ZWave To MQTT', + storeDir: 'store', + base: '/', + port: 8091 +} diff --git a/config/index.js b/config/index.js index be7bec17..91271a4b 100644 --- a/config/index.js +++ b/config/index.js @@ -13,9 +13,9 @@ module.exports = { '/socket.io': { target: 'ws://localhost:8091', ws: true - }, - '/health': 'http://localhost:8091', - '/api': 'http://localhost:8091' + }, + '/health': 'http://localhost:8091', + '/api': 'http://localhost:8091' }, // Various Dev Server settings diff --git a/config/webConfig.js b/config/webConfig.js index 87af02de..10ef04b8 100644 --- a/config/webConfig.js +++ b/config/webConfig.js @@ -1,13 +1,13 @@ -const appConfig = require('./app'); +const appConfig = require('./app') appConfig.base = appConfig.base && appConfig.base.replace(/\/?$/, '/') const defaultConfig = { - base: '/', - title: 'ZWave To MQTT' -}; + base: '/', + title: 'ZWave To MQTT' +} module.exports = { - ...defaultConfig, - ...appConfig -}; + ...defaultConfig, + ...appConfig +} diff --git a/docs/subpath.md b/docs/subpath.md index df7d702e..978afdcf 100644 --- a/docs/subpath.md +++ b/docs/subpath.md @@ -53,9 +53,9 @@ would look like: ```javascript module.exports = { - 'title': 'ZWave to MQTT', - 'storeDir': 'store', - 'base': '/zwave/', - 'port': 8091 -}; + title: 'ZWave to MQTT', + storeDir: 'store', + base: '/zwave/', + port: 8091 +} ``` diff --git a/lib/renderIndex.js b/lib/renderIndex.js index a79d8f9c..0adb928e 100644 --- a/lib/renderIndex.js +++ b/lib/renderIndex.js @@ -7,11 +7,13 @@ const webConfig = reqlib('/config/webConfig') function findFiles (folder, ext) { const folderPath = path.join(__dirname, '..', 'dist', folder) const folderFiles = fs.readdirSync(folderPath) - return folderFiles.filter(function (file) { - return path.extname(file).toLowerCase() === `.${ext.toLowerCase()}` - }).map(function (file) { - return path.join(folder, file) - }) + return folderFiles + .filter(function (file) { + return path.extname(file).toLowerCase() === `.${ext.toLowerCase()}` + }) + .map(function (file) { + return path.join(folder, file) + }) } let cssFiles diff --git a/src/App.vue b/src/App.vue index aabbf8f8..03703d7a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,10 +4,15 @@ - + - {{"ZWave2MQTT v" + version}} + {{ + 'ZWave2MQTT v' + version + }} @@ -48,7 +53,8 @@ style="cursor:default;" :color="statusColor || 'primary'" v-on="on" - >swap_horizontal_circle + >swap_horizontal_circle {{ status }} diff --git a/src/apis/ConfigApis.js b/src/apis/ConfigApis.js index 26d65b89..5e8993ce 100644 --- a/src/apis/ConfigApis.js +++ b/src/apis/ConfigApis.js @@ -15,7 +15,10 @@ export default { return getBasePath() }, getSocketPath () { - const innerPath = document.baseURI.split('/').splice(3).join('/') + const innerPath = document.baseURI + .split('/') + .splice(3) + .join('/') const socketPath = `/${innerPath}/socket.io`.replace('//', '/') return socketPath === '/socket.io' ? undefined : socketPath }, diff --git a/test/lib/renderIndex.test.js b/test/lib/renderIndex.test.js index 5e931368..1e28982a 100644 --- a/test/lib/renderIndex.test.js +++ b/test/lib/renderIndex.test.js @@ -32,18 +32,24 @@ describe('#renderIndex', () => { }) it('uses the base from the `X-External-Path` header', () => { - renderIndex({ - headers: { - 'x-external-path': '/test/base' - } - }, mockResponse) + renderIndex( + { + headers: { + 'x-external-path': '/test/base' + } + }, + mockResponse + ) lastOptions.config.base.should.equal('/test/base/') }) it('uses configured value if no header is present', () => { - renderIndex({ - headers: {} - }, mockResponse) + renderIndex( + { + headers: {} + }, + mockResponse + ) lastOptions.config.base.should.equal('/configured/path/') }) }) @@ -63,9 +69,12 @@ describe('#renderIndex', () => { it('When no dist files present it will have empty css and js files', () => { mockedReaddir.returns([]) - renderIndex({ - headers: {} - }, mockResponse) + renderIndex( + { + headers: {} + }, + mockResponse + ) lastTpl.should.equal('index.ejs') lastOptions.cssFiles.should.eql([]) lastOptions.jsFiles.should.eql([]) @@ -75,19 +84,16 @@ describe('#renderIndex', () => { console.log(cssFolder) mockedReaddir .withArgs(cssFolder) - .returns([ - 'valid-css.css', - 'invalid-css.scss' - ]) + .returns(['valid-css.css', 'invalid-css.scss']) mockedReaddir .withArgs(jsFolder) - .returns([ - 'valid-js.js', - 'invalid-js.map' - ]) - renderIndex({ - headers: {} - }, mockResponse) + .returns(['valid-js.js', 'invalid-js.map']) + renderIndex( + { + headers: {} + }, + mockResponse + ) lastTpl.should.equal('index.ejs') lastOptions.cssFiles.should.eql(['static/css/valid-css.css']) lastOptions.jsFiles.should.eql(['static/js/valid-js.js']) From 35efeca25c37e0de6003d32348f650832a1b537e Mon Sep 17 00:00:00 2001 From: fabio-torchetti <53441171+fabio-torchetti@users.noreply.github.com> Date: Fri, 5 Jun 2020 19:06:19 -0500 Subject: [PATCH 29/33] Update README.md Co-authored-by: Chris Nesbitt-Smith --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5ee3e4b..bcd33aca 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ kubectl apply -k https://raw.githubusercontent.com/openzwave/zwave2mqtt/master/k ### Reverse Proxy Setup If you need to setup ZWave To MQTT behind a reverse proxy that needs a _subpath_ to -work, take a look at [this](docs/subpath.md). +work, take a look at [the reverse proxy configuraiton docs](docs/subpath.md). ## :nerd_face: Development From 13812500560ff633e13196cc53ef9bed3188ba39 Mon Sep 17 00:00:00 2001 From: fabio-torchetti <53441171+fabio-torchetti@users.noreply.github.com> Date: Fri, 5 Jun 2020 19:06:40 -0500 Subject: [PATCH 30/33] Update build/webpack.dev.conf.js Co-authored-by: Chris Nesbitt-Smith --- build/webpack.dev.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index 51ef3968..ac58d3f5 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -55,7 +55,7 @@ const devWebpackConfig = merge(baseWebpackConfig, { new webpack.NoEmitOnErrorsPlugin(), // https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ - title: 'ZWave To MQTT', + title: 'ZWave To MQTT', filename: 'index.html', template: 'views/index.ejs', templateParameters: { From bd00ec94ed4eeeddcc178260f09a1a33a52f16d1 Mon Sep 17 00:00:00 2001 From: fabio-torchetti <53441171+fabio-torchetti@users.noreply.github.com> Date: Fri, 5 Jun 2020 19:28:21 -0500 Subject: [PATCH 31/33] Update src/App.vue Co-authored-by: Chris Nesbitt-Smith --- src/App.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.vue b/src/App.vue index 03703d7a..4b651ad4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -218,7 +218,7 @@ export default { var self = this - this.socket = this.socket = io('/', { + this.socket = io('/', { path: ConfigApis.getSocketPath() }) From 791d7aac5a47a48f38a4744991775ef8bf45e696 Mon Sep 17 00:00:00 2001 From: fabio-torchetti <53441171+fabio-torchetti@users.noreply.github.com> Date: Fri, 5 Jun 2020 19:31:23 -0500 Subject: [PATCH 32/33] Update test/lib/renderIndex.test.js Co-authored-by: Chris Nesbitt-Smith --- test/lib/renderIndex.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/renderIndex.test.js b/test/lib/renderIndex.test.js index 1e28982a..c0deb904 100644 --- a/test/lib/renderIndex.test.js +++ b/test/lib/renderIndex.test.js @@ -40,7 +40,7 @@ describe('#renderIndex', () => { }, mockResponse ) - lastOptions.config.base.should.equal('/test/base/') + return lastOptions.config.base.should.equal('/test/base/') }) it('uses configured value if no header is present', () => { From c303f8e0584d599113c0420ffa7e745a2dc3e26e Mon Sep 17 00:00:00 2001 From: Fabio Torchetti Date: Fri, 5 Jun 2020 19:36:40 -0500 Subject: [PATCH 33/33] Make proxy URL configurable; UT fixes --- README.md | 13 +++++++++++++ config/index.js | 21 ++++++++++++++++++--- test/lib/renderIndex.test.js | 1 - 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bcd33aca..5724c377 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,19 @@ In the second terminal run `npm run dev:server` to start the backend server with To package the application run `npm run pkg` command and follow the steps +### Developing against a different backend + +By default running `npm run dev:server` will proxy the reequests to a backend listening on _localhost_ on port _8091_. + +If you want to run the development frontend against a different backend you have the following environment variables +that you can use to redirect to a different backend: + +- **SERVER_HOST**: [Default: 'localhost'] the hostname or IP of the backend server you want to use; +- **SERVER_PORT**: [Default: '8091'] the port of the backend server you want to use; +- **SERVER_SSL**: [Default: undefined] if set to a value it will use _https_/_wss_ to connect to the backend; +- **SERVER_URL**: [Default: use the other variables] the full URL for the backend API, IE: `https://zwavetomqtt.home.net:8443/` +- **SERVER_WS_URL**: [Default: use the other variables] the full URL for the backend Socket, IE: `wss://zwavetomqtt.home.net:8443/` + ## :wrench: Usage Firstly you need to open the browser at the link and edit the settings for Zwave, MQTT and the Gateway. diff --git a/config/index.js b/config/index.js index 91271a4b..b7faa6d1 100644 --- a/config/index.js +++ b/config/index.js @@ -4,6 +4,21 @@ const path = require('path') +const proxyScheme = process.env.SERVER_SSL ? 'https' : 'http' +const proxyWebSocketScheme = process.env.SERVER_SSL ? 'wss' : 'ws' +const proxyHostname = process.env.SERVER_HOST + ? process.env.SERVER_HOST + : 'localhost' +const proxyPort = process.env.SERVER_PORT ? process.env.SERVER_PORT : '8091' + +const proxyURL = process.env.SERVER_URL + ? process.env.SERVER_URL + : `${proxyScheme}://${proxyHostname}:${proxyPort}` + +const proxyWSURL = process.env.SERVER_WS_URL + ? process.env.SERVER_WS_URL + : `${proxyWebSocketScheme}://${proxyHostname}:${proxyPort}` + module.exports = { dev: { // Paths @@ -11,11 +26,11 @@ module.exports = { assetsPublicPath: '/', proxyTable: { '/socket.io': { - target: 'ws://localhost:8091', + target: proxyWSURL, ws: true }, - '/health': 'http://localhost:8091', - '/api': 'http://localhost:8091' + '/health': proxyURL, + '/api': proxyURL }, // Various Dev Server settings diff --git a/test/lib/renderIndex.test.js b/test/lib/renderIndex.test.js index c0deb904..7f236454 100644 --- a/test/lib/renderIndex.test.js +++ b/test/lib/renderIndex.test.js @@ -81,7 +81,6 @@ describe('#renderIndex', () => { }) it('When dist files present will only return the ones with the correct extensions', () => { - console.log(cssFolder) mockedReaddir .withArgs(cssFolder) .returns(['valid-css.css', 'invalid-css.scss'])