In a previous post, I showed you how to add Angular's Service Worker (NGSW) module to an Ionic project.
In this post, I'll show you how to optimise your CSS delivery.
Step 1 - Create a Production build
We'll start by creating a production build:
npm run build --prod
Now check your project's www/build
directory:
305 KB, that seems like a lot!
Step 2 - Create a Sass configuration file
To get Ionic Apps up and running quickly version 3 of the Ionic Framework includes Ionic App Scripts.
@ionic/app-scripts
provides default configuration files for each of it's build tasks, we can override the defaults by providing our own configuration files.
sass.config.js
@ionic/app-scripts
default Sass configuration file describes the Sass files and options required to compile a project.
I created a copy of the file in my project's config directory:
├── /brew
└── /config
├── sass.config.js
├── webpack.config.js
└── /e2e
└── /node_modules - Packages managed by npm
└── /src - Angular scripts
...
└── /www - Ionic's 'dist' folder
├── package.json
├── tsconfig.ts
...
Note: Check out this post about webpack configuration.
Let's take a look at the file's excludeFiles
section:
/**
* excludeFiles: An array of regex patterns for files which
* should be excluded. If a file matches both include and exclude
* patterns, then the file will be excluded.
*/
excludeFiles: [
/* /\.(ios|md|wp).(scss)$/i */
],
My PWA needs to support Android:
And iOS:
So we can update the excludeFiles
section as follows:
excludeFiles: [
/\.(wp).(scss)$/i
],
You can also exclude the Sass files of the components that your project doesn't use:
excludeFiles: [
/\.(wp).(scss)$/i,
/(backdrop|chip|note|picker| ... |cordova)/i
],
variables.scss
I also updated variables.scss
as follows:
...
$colors: (
primary: $blue,
);
// @import "ionic.ionicons";
...
Note: Check out this post about theming your Ionic App using SVG icons and this post about Ionic's $colors map.
Step 3 - Create a Copy configuration file
@ionic/app-scripts
also provides a default configuration file for the copy task, we can override the defaults by providing our own configuration file.
copy.config.js
@ionic/app-scripts
default Copy configuration file describes the static assets to copy to the www
directory.
I created a copy of the file in my project's config directory:
├── /brew
└── /config
├── copy.config.js
├── sass.config.js
├── webpack.config.js
└── /e2e
└── /node_modules - Packages managed by npm
└── /src - Angular scripts
...
└── /www - Ionic's 'dist' folder
├── package.json
├── tsconfig.ts
...
And updated it as follows:
module.exports = {
copyAssets: {
src: ['{{SRC}}/assets/**/*'],
dest: '{{WWW}}/assets'
},
copyIndexContent: {
src: ['{{SRC}}/index.html',
'{{SRC}}/favicon.ico',
'{{SRC}}/apple-touch-icon.png',
'{{SRC}}/apple-touch-icon-precomposed.png',
'{{SRC}}/manifest.json',
'{{SRC}}/browserconfig.xml'],
dest: '{{WWW}}'
},
copyFonts: {
src: ['{{ROOT}}/node_modules/ionic-angular/fonts/noto-sans**',
'{{ROOT}}/node_modules/ionic-angular/fonts/roboto**'],
dest: '{{WWW}}/assets/fonts'
},
copyPolyfills: {
src: [`{{ROOT}}/node_modules/ionic-angular/polyfills/${process.env.IONIC_POLYFILL_FILE_NAME}`],
dest: '{{BUILD}}'
},
copySwToolbox: {
src: ['{{ROOT}}/node_modules/sw-toolbox/sw-toolbox.js'],
dest: '{{BUILD}}'
}
};
package.json
Ionic projects use the package.json
file for configuration. I updated it as follows:
"config": {
"ionic_copy": "./config/copy.config.js",
"ionic_sass": "./config/sass.config.js",
"ionic_webpack": "./config/webpack.config.js"
}
Now we can update our production build:
npm run build --prod
And check the project's www/build
directory:
176 KB, better but it still seems like a lot.
Step 4 - Optimise CSS Delivery
I followed the advice of the PageSpeed Tools Insights and used the Critical Path CSS Generator to inline a small CSS file:
<head>
...
<style>
.first-meaningful-paint{background-image:url( ...
</style>
</head>
I also load CSS files that are not critical to the initial rendering of the App, asynchronously:
...
<body>
<ion-app></ion-app>
<script src="build/polyfills.js"></script>
<script src="build/vendor.js"></script>
<script src="build/main.js"></script>
<link rel="preload" href="build/main.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="build/main.css"></noscript>
</body>
Now we're ready to perform an audit in Chrome's DevTools:
Good, but not great! There's still room for improvement :)
What's Next
In the next post, I'll walk you through the Progressive Web App-related tips and tricks I've learned over the past few months.
Resources:
- GitHub: Ionic App Scripts
- PageSpeed Tools Insights: Optimize CSS Delivery
- Jonas Ohlsson Aden: Critical Path CSS Generator
- GitHub: loadCSS
- Rob Ferguson's blog: Theming your Ionic 3 App - Bespoke SVG icons
- Rob Ferguson's blog: Theming your Ionic 3 App - The $colors map
- Rob Ferguson's blog: Working with TypeScript, webpack and Ionic 3
Additional Resources:
- GitHub: Angular Performance Cheatsheet
- oasis digital blog: Angular Runtime Performance Guide
- GitHub: Awesome list of Progressive Web Apps