After converting one minimal layout to CH5, I should be an expert, right? I purposely waited a week so that time would temper my emotions a bit (I was a little frustrated by the end of the last post). I wouldn’t say I’m going to give it 10,000 hours, but I think it’s only fair to invest some more time than I initially gave it. This could be a decent framework for converting touchpanel layouts, maybe I just need more exposure.
One word comes to mind when I think back to converting a full layout: slog. It felt like I was constantly fighting the CH5 styles to match what I had mocked up in VT Pro. I kept stopping, thinking, This doesn’t feel right, what am I doing wrong? For example, a transparent button is a common element in VT Pro but doesn’t come standard with CH5. I experimented with a few different ways to get the desired effect, but which way is the right way–the Crestron way?
Maybe this is just a challenge that all web developers face? I did learn HTML and JavaScript 20 years ago to build a personal homepage. Add in CSS a little later, and I could at least understand how content on a webpage was created. I was also painfully aware at the time that Microsoft had their own way of doing things that didn’t always match the “standard.” But since Microsoft had dominant market share, everyone had to accommodate their quirks. Fast forward to 2021, and a lot of the pain of web development has been abstracted away by using a framework, and (thankfully) Microsoft isn’t calling all the shots anymore. Looking at JavaScript from 2001 vs 2021, it’s almost like two different languages. I have a lot of catching up to do.
When I’m feeling lost, I usually start with the documentation.
The Documentation
There is a lot of material to read through on the CH5 developer site. Here’s a checklist of technologies you need to know to really understand what’s going on in the Shell Template:
- Visual Studio Code This seems to be the environment the web dev world has settled on. It’s pretty easy to setup and use, it works cross-platform, and it’s free.
- Node.js and NPM This goes hand-in-hand with web development now. It’s a huge, messy ecosystem compared to NuGet. Some packages should not exist. You’ll use it as a hybrid package manager / build system.
- Yarn This is just another package manager, it does the same thing as NPM. I guess it used to be significantly faster, but that’s not true anymore.
- Webpack This is a bundler that packages everything your app needs into a file ready for distribution.
- JSON There is a project-config.json file that controls some aspects of how the template behaves.
- SCSS and SASS The template uses Bootstrap SCSS for theming, so you’ll need to know it to change the look of things.
- CH5 Components Like ch5-button and ch5-list. These are how you structure the content of your UI pages. ch5-triggerview is the most useful component I’ve seen so far.
- CH5 Custom Attributes Like data-ch5-textcontent and data-ch5-show. These are how you can control the UI from the control system.
- Single-Page Applications SPAs are how you design a user interface that lives on a device (like a touchpanel). They only update the pieces they need to rather than fetching a whole new page every time. This makes the UI updates much quicker and contributes to a better user experience.
There you go. Go learn all those things first, then we can dig into the Shell Template.
How does the template project get built?
This is the first question I had. I’m not very familiar with JavaScript frameworks, so maybe this isn’t such a mystery to others. Lets take a look at the start
NPM script:
yarn val:pc && yarn clean:start && webpack --config webpack.dev.js
The first thing this does is run the val:pc
script which runs
node shell-utilities/project-config/validate-json.js
This is a helper script that reads in the /app/project-config.json file and validates it against a schema. It also checks that we’ve defined some pages, some widgets, that we didn’t repeat any, that we selected a valid theme, etc. This script collects any errors together and spits them out to the console. For example, if I change selectedTheme
to one that doesn’t exist, I get:
Validating project-config.json......
Errors Found (1):
1. Invalid selected theme: Selected theme 'foobar' is not available in the list of themes.
error Command failed with exit code 1.
As long as the config file validates successfully, the next script that runs is clean:start
which does:
rimraf dist/dev
This deletes everything under the dist/dev folder (including the dev folder). The last part of the start
script runs webpack --config webpack.dev.js
. Here’s where things get… complicated.
Webpack
First off, what is Webpack? It a nutshell, Webpack scans your project for all the required dependencies and bundles them together. This makes it easier to develop modules and make things work in a web browser. Webpack is like make for web dev. What specifically does webpack.dev.js contain?
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WriteJsonPlugin = require('write-json-webpack-plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const common = require('./webpack.common.js');
const pkg = require('./package.json');
const BrowserSyncPlugin = require("browser-sync-webpack-plugin");
const appConfig = require('./app.config');
const projectConfig = require("./app/project-config.json");
const srcRoot = appConfig.srcRoot;
The highlighted lines show we’re pulling more configuration from app.config but also importing /app/project-config.json. We can check the list of plugins
that get called to see how Webpack builds a development release:
plugins: [
new ConcatPlugin({
uglify: false,
sourceMap: false,
name: 'result',
outputPath: 'libraries/',
fileName: 'cr-com-lib.js',
filesToConcat: jsList,
attributes: {
async: true
}
}),
new ConcatPlugin({
uglify: false,
sourceMap: false,
name: 'result',
outputPath: 'libraries/',
fileName: 'component.js',
filesToConcat: componentsList,
attributes: {
async: true
}
}),
new WriteJsonPlugin({
object: appVersionInfo,
path: 'assets/data/',
filename: 'app.manifest.json',
flatten: true,
pretty: true
}),
new HtmlWebpackPlugin({
filename: 'index.html',
inject: false,
template: './app/index.html'
}),
new BrowserSyncPlugin({
host: "localhost",
port: 3000,
files: ["./" + distPath + "/**/**/*.html", "./" + distPath + "/**/**/**/*.js", "./" + distPath + "/**/**/**/*.css"],
server: {
baseDir: [distPath]
}
})
]
That last BrowserSyncPlugin
will open a web browser pointed to our development server that automatically refreshes if any watched files change. Very handy when you’re trying things out and want to see the changes immediately.
The meat of the Shell Template comes from componentsList
. If we inspect its contents, we see that it contains:
./app/template/libraries/crcomlib-polyfill.js
./app/template/libraries/service.js
./app/template/libraries/translate.js
./app/template/libraries/utils.js
./app/template/libraries/webxpanel.js
./app/template/components/pages/template-content/template-content.js
./app/template/components/pages/template-footer/template-footer.js
./app/template/components/pages/template-header/template-header.js
./app/template/components/pages/template-index/template-index.js
./app/template/components/widgets/template-remote-logger-settings/template-remote-logger-settings.js
./app/template/components/widgets/template-version-info/template-version-info.js
./app/project/components/pages/contacts/contacts.js
./app/project/components/pages/content/content.js
./app/project/components/pages/dial/dial.js
./app/project/components/pages/home/home.js
And if you look in /dist/dev/Shell/libraries/component.js, you can see how Webpack has merged all of these files into one where all dependencies are met.
I thought we were talking about CH5…
Right! Some digging into how the Shell Template gets built has given me a better idea about how the framework stitches together. For example, I don’t like the template layout, so I would probably ditch most of that if I were to keep working with CH5 components.
How exactly do the components get pulled in? If we dig into the /dist/dev/Shell folder, we can see how index.html gets put together. At the end of the body, we can see the two scripts that Webpack bundled:
<!-- inject:js -->
<script src="./libraries/cr-com-lib.js"></script>
<script src="./libraries/component.js"></script>
<!-- endinject -->
If you scroll through component.js, you’ll see all the individual JavaScript modules we created are concatenated together. Some of it comes from the template folder, some of it comes from the project folder. You can see that starting with the Shell Template is building on top of a large technology stack.
Is it worth it?
This is a tough question to answer just yet. I think Crestron has done a good job trying to provide something that will get you up and running with an HTML5 layout, but I think it’s difficult to customize. And then there’s the entire cr-com-lib.js which is built from minified code so you can’t really tell what’s going on. This is one area where an open source framework would be better to use since the documentation is more thorough, there are thousands of examples spread across the Internet, you can get help from others in the web dev industry, and–all else fails–you can read the code of the framework itself. With CH5, you’re limited to only a few outlets for help.
Crestron has a few CH5 sessions listed for Masters 2021, and I’m hoping I’ll be able to attend all of them to get a better handle on how they want us to use their framework. I think it’s still worthwhile to learn and develop with, but I don’t think I would ever want to use it exclusively.