Additionally to using Twilio Assets to host audio files for your phone calls or files for shared logic between your Twilio Functions you can also use it to serve front-end web assets such as HTML, JS and CSS files.
In this guide we'll talk about how you can use the Serverless Toolkit to use front-end frameworks to build you web assets. As an example we'll be using React as a front-end framework but you can use any common framework including Vue and Angular.
If you don't already have an existing project using the Serverless Toolkit, go ahead and create one by following the instructions in our Getting Started guide. Otherwise, keep reading.
In this guide we'll be using Parcel as our build tool of choice but you can apply similar steps to Webpack or other bundlers.
Make sure to install your bundler tool in the devDependencies
section of your package.json
.
To install Parcel run:
npm install parcel-bundler --save-dev
By default a project created with the Serverless Toolkit will contain a functions/
and an assets/
directory. In our case we'll want to keep the two directories but we'll also add two new directories:
src/
will contain our front-end code that we'll end up passing through the Parcel Bundlerdist/
will serve as the source of truth for the assets that we'll deploy. In our case this will be a combination of the bundled assets from src/
and the static files from the assets/
directory.Create the src/
directory and add an index.html
file to it as this will serve as the entry point for our bundler.
This is where you'll reference other files that should be bundled such as stylesheets or JavaScript files. For more information, make sure to check out the Parcel documentation.
Since the dist/
directory contains bundled files it does not make sense to version control this directory. Instead make sure to add it to your .gitignore
file at the root of your project.
dist/
We'll be using two other tools:
concurrently
to run the Parcel build process at the same time as twilio-run
to serve our project.ncp
to copy files from assets/
to dist/
rimraf
to delete the dist/
directory before building the AssetsInstall the two dependencies by running:
npm install concurrently ncp --save-dev
By default the Serverless Toolkit will use the assets/
directory to serve and deploy Twilio Assets.
You can modify this behavior by using the --assets-folder
flag but the easier way is by creating/modifying your .twilioserverlessrc
file at the root of your project the following way:
1{2"commands": {},3"environments": {},4"projects": {},5// "assets": true /* Upload assets. Can be turned off with --no-assets */,6"assetsFolder": "dist" /* Specific folder name to be used for static assets */,7// ..8}
Next we need to define a couple of "scripts"
inside our package.json
to make executing the right steps easier.
Modify the scripts
section of your package.json
the following way:
1"scripts": {2"prebuild": "rimraf dist",3"build": "parcel build src/index.html -d dist",4"postbuild": "ncp assets dist",5"predeploy": "npm run build",6"deploy": "twilio-run deploy",7"start:web": "parcel watch src/index.html -d dist",8"start:twilio": "twilio-run",9"prestart": "ncp assets dist",10"start": "concurrently npm:start:web npm:start:twilio"11},
This way you'll have three distinct commands:
npm start
will start the build server for Parcel and serve all Assets and Functions locally using twilio-run
npm run build
to build all front-end assets and copy over all static files from assets/
npm run deploy
will run npm run build
and take all files in dist/
and deploy them together with all Functions from functions/
to Twilio Functions.If you are using twilio serverless:deploy
to deploy your application instead of twilio-run
you have to manually run npm run build
first and then can normally deploy using twilio serverless:deploy
.
Now that we set up our build chain you can start developing your project.
Most things should work as you are used to but there are a few things to keep in mind.
All dependencies for your UI should be installed as devDependencies
unless they are also used from within your Functions. For example, let's say we want to use React with Twilio's Paste Design System. We'd install the dependencies the following way:
npm install react react-dom prop-types @twilio-paste/core @twilio-paste/icons --save-dev
Note the --save-dev
at the end. If you are using yarn
or pnpm
both of them support equivalent flags to store dependencies as devDependencies
.
If you do not install them as devDependencies
but as dependencies
instead, they'll be installed in your Twilio Functions deployment which increased deployment times and might cause other unintended side effects including failed builds.
When you run npm run deploy
or twilio serverless:deploy
the tool will automatically deploy everything in the dist/
folder but nothing else. Meaning if you are building your output files with file hashes in the name (e.g. main.a124bfc.js
) and the build changes that hash to a different one (e.g. main.a12222f.js
) and you deleted the dist/
folder prior to building (default in the scripts above) this will result in main.a124bfc.js
to not be served anymore post deployment. The Serverless Toolkit currently does not support additive deployments that would support both versions to be available.
On the flip-side keeping your dist/
folder as lean as possible will reduce the deployment time.
With the setup described above you should be able to call any of your Functions that exist in the functions/
directory by specifying the absolute path of them. For example for a Function with the file functions/token.js
you can make an HTTP request from within your front-end to /token
.
For example:
1fetch('/token')2.then(response => response.json())3.then(data => {4console.log(data);5});
We talked about "static" assets above? What are those and why are we keeping those separately in a assets/
. With static assets in this case we mean any file we don't want to have processed by our build tooling. Common types of such assets could be media files — for example an mp3 file that you are referencing in the TwiML for your Twilio Voice call — or a private JavaScript module that you are referencing for from one of your Twilio Functions to store shared logic. In general private assets are likely going to be static assets that you might want to store in the assets/
directory.
At the current moment Twilio Assets does not support the following two features that you might have to consider when building your front-end on Twilio Serverless:
react-router
unless you are operating them in a hash-based routing mechanism. You'll always have to serve to specify the full URL. The only current exception is if you have a file with the path /assets/index.html
you can use /
to reference the same file. In our case this means that you'd have to have Parcel output a file in the directory dist/assets/index.html
which then, once deployed, will be available both at https://<service_name>-<number>-<environment_suffix>.twil.io/
and https://<service_name>-<number>-<environment_suffix>.twil.io/assets/index.html
.