ionicons icon indicating copy to clipboard operation
ionicons copied to clipboard

Icon deployment in production apps

Open cjorasch opened this issue 7 years ago • 3 comments

There are a couple of issues with the current icon approach used by Ionic when used in a production application.

Performance

Icons are "all or nothing" in the application. A typical app might use 5-20 icons but the build process results in 700 icons with a total size of almost 3mb in the svg folder in the build output.

The service worker pre-cache manifest includes all of these icons (2800 lines of code) even if you only use a single icon. The service worker also loads all of these icons into the cache (3mb) This uses network traffic, blocks other loading, and uses limited available local storage space.

Lazy loading

Icons are lazy loaded as individual files when it would sometimes be faster to inline them into component files. I have noticed that the stencil site project uses inline svg to help with this. If an icon is only used by a single component then it results in an extra round trip to the server.

Cache headers

Cache headers are difficult to specify for icon content. Javascript and css uses hash versions in the file names so that it possible to use "cache forever" headers on the content and know that old versions will be replaced. This does not work with icons. If "cache forever" is used then the icons can never be updated. If "cache for x days" is used then there will be lots of round trips to check for new versions even though the icons are very unlikely to change.

Alternate approach

A potential alternate approach would be to use standard js imports for the content.

For example:

// ionic/icons
export const svgAirplane = '<svg xmlns="http://www.w3.org/2000/svg" ... ';
export const svgAlarm = '<svg xmlns="http://www.w3.org/2000/svg" ... ';
// etc.

// my-component.tsx
import { svgAlarm } from '@ionic/icons';
import { myIcon } from './my-icon';
render() {
    return (
        <div>
            <ion-icon icon={svgAlarm} />;
            <ion-icon icon={myIcon} />;
        </div>
    );
}

Some of the benefits of this approach include:

  • Only icons that are used get built into the app.
  • Icons get inlined into components or chunks using the standard build process.
  • Inline icons are displayed synchronously for faster initial display.
  • "Cache forever" can be used because all file references are versioned already.
  • Custom icons can be used if <ion-icon> accepts svg vs. name.

Some potential issues with this approach:

  • How to handle mode specific icons

cjorasch avatar May 10 '18 22:05 cjorasch

I'm new to ionicons and I was worried about bundling a large file just for a few icons. What needs to be done to implement the recommendation above? Can I go ahead and import specific icons as recommended or are there any upstream changes pending to make this work?

mrcasablr avatar May 26 '18 04:05 mrcasablr

@mrcasablr and anyone else coming across this thread: if you happen to be using a babel-based build stack there is a babel-plugin-inline-import plugin that converts whatever the reference source file is to text. This works beautifully for SVG's since they are just text.

If you are using stencil, there is an inlineAssetsMaxSize field in the stencil config that can be used, but it is a sledgehammer that will inline all assets, not just SVG's.

codinronan avatar Jul 08 '18 19:07 codinronan

This issue has been labeled as help wanted. This label is added to issues that we believe would be good for contributors.

If you'd like to work on this issue, please comment here letting us know that you would like to submit a pull request for it. This helps us to keep track of the pull request and make sure there isn't duplicated effort.

For a guide on how to create a pull request and test this project locally to see your changes, see our contributing documentation.

Thank you!

ionitron-bot[bot] avatar Apr 21 '25 16:04 ionitron-bot[bot]