Using a bundler
- .gs files – these are intended to be run server side
- .html files – these are intended to be used as input to htmlservice
In this pattern we’ll expand on these file types a bit
- .gs files – these are server side files, but can also be included client side to allow common code to run both server side and client side. Of course .gs files that contain references to Apps Script services can only run server side, but everything else is fair game.
- .html files – these should contain markup html only
- .css.html – css style files
- .vue.html – vue scripts
There’s no need to include <script>, <style> tags etc, as they will be inserted automatically if needed.
The index file is used to organize the finally bundled htmlservice app. Here’s an example of a full app that include various of the above examples. The most complex is the .mjs file, which is for importing modules – often directly from the npm cdn
Many apps will include script files and css from a cdn – best to keep those separate.
The entire app has a namespace named Store – into which the majority of app resources are. The idea is that the code for Vue components are each added to this store – so the here’s how a vue file for htmlservice would like and how it would be added to the store
Each component is listed in the index.html, and each component file would be defined as the above example. Here’s a list of components used in this app
First a couple of points on importing.
- <script type=”module”> introduces the capability of importing modules.
- Most npm modules are automatically available at https://cdn.skypack.dev/[npmmodule]
- Although some of these modules include bundled versions, not all do, so you have to use module importing to get access to them
- Imports are scoped to within the <script type=”module”></script> tags, whereas normally <script></script> will include its contents in the global space.
- Imports are asynchronous
These things together mean that we need some measures to be able to mix modules, and traditional scripts. Include.mjs takes care of all of this. Heres an example.
The idea is that a single object will hold all the imported modules in the form of a promise, which will be resolved when all the requested modules are finished importing. Later in the app, the Promise can be tested for resolution and the modules available for use.
mjs Property descriptions
An mjs include definition has these properties
|sources||The list of sources from where to import the modules|
|promiseName||The name of the variable (or object property) that will hold the promise that will be resolved when all the modules have been imported|
|initialize||Whether or not the promiseName needs to be created as a global variable|
sources property descriptions
Each source element has these properties
|key||This is how the module will be known later|
|src||This is from where the module should be imported|
|exportName||Depending on whether the module is a named export, but most npm modules will be ‘default’|
It’s worth taking a quick look at exactly what code will get generated from our Include definition
At some later point, when the imported modules are needed, we can wait till the promise resolution before continuing. This is the complete main.js for the app.
Importing external vue components
We used Include.vue to add components which were defined local to this project, but ideally we’d like to be able to have access to the many vue components available on npm. These are typically not bundled as they are expected to be used in a Node development environment. However we can use exactly the same module import method to include them in your apps script Vue app.
Note above that a country flag module has been imported – now we can simply add that to our local components
Of course the order of including is still important, but following a few basic guidelines can avoid lots of wasted time. The key points here are that we can
- Access all modules on npm and include them in our htmlservice app
- Reuse code between client and server
- Import ready made Vue components