More Interactivity (Typescript)
The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages and pre-processors such as Typescript and Sass.
I've used Parcel on several projects and before that Webpack. I've found Parcel to be easier to use and so that is the recommendation for Nails.
Setting up a Volume
If you look at your .devcontainer/docker-compose.yml
you'll see a line that is commented out.
#- node_modules:/workspace/crates/asset-pipeline/node_modules # Set target as a volume for performance.
Comment that back in and rebuild your devcontainer. This will setup the node_modules folder as a volume and you will get way better performance during builds. This is due to the fact the node_modules folder has many files and docker tries to sync them with your main file system.
Also in your .devcontainer/Dockerfile
uncomment the following line.
#RUN sudo mkdir -p /workspace/crates/asset-pipeline/node_modules && sudo chown $USERNAME:$USERNAME /workspace/crates/asset-pipeline/node_modules
.gitignore
We need the following .gitignore
file.
dist node_modules .parcel-cache
Installing Parcel
To install parcel
$ mkdir crates/asset-pipeline $ cd crates/asset-pipeline $ npm install --save-dev parcel
Now create an crates/asset-pipeline/index.ts
import './scss/index.scss'
And also crates/asset-pipeline/scss/index.scss
h1 { color: red; }
Add a scripts section to your package.json
"scripts": { "start": "parcel watch ./asset-pipeline/index.ts", "release": "parcel build ./asset-pipeline/index.ts" },
npm run start
And now when you run npm install & npm run start
parcel will generate your assets into the dist folder. We should also update our ./.gitignore
to exclude the generated files.
/target .parcel-cache /app/dist node_modules
Adding Images
Create an empty images folder in crates/asset-pipeline/images
then your project should now look something like this.
. ├── .devcontainer/ │ └── ... └── crates/ │ asset-pipeline/ │ ├── .gitignore │ ├── images/ │ │ └── ... │ ├── index.scss │ ├── index.ts │ └── node_modules/ │ └── ... │ web-server/ │ │ └── main.rs │ └── Cargo.toml │ db/ │ └── ... ├── .gitignore ├── Cargo.toml └── Cargo.lock
What we have
We now have a pipeline to compile Typescript and SCSS assets and a place to store images.
The islands architecture encourages small, focused chunks of interactivity within server-rendered web pages. The output of islands is progressively enhanced HTML, with more specificity around how the enhancement occurs. Rather than a single application being in control of full-page rendering, there are multiple entry points. The script for these "islands" of interactivity can be delivered with web components, allowing the rest of the page to be just static HTML.
Implementing islands architecture
There are several ways to support the islands architecture for example Stimulus, which I've used on multiple projects.
However all modern browser come with web components built in and as they are pretty simple to use it makes sense to implement client side enhancement using this technology.
Example WebComponent
An example of a very simple component create the following in crates/asset-pipelines/components/hello_world.ts
.
//define a class extending HTMLElement class HelloWorld extends HTMLElement { connectedCallback () { this.innerHTML = 'Hello, World!' } } //register the new custom element customElements.define( 'hello-world', HelloWorld )
Include the element into your app/src/asset-pipeline/index.ts
i.e.
import './scss/index.scss' import './components/hello_world.ts'
To use the element
<hello-world></hello-world>