Skip to content

Migrate widget to Manifest V2

Mark van Dijk edited this page Oct 7, 2021 · 11 revisions

Why?

Because 'externals' are now supported! This allows you to keep the widget bundle size small(er) and depend on modules (dependencies) loaded centrally by the Widget Board solution.

Do I need to?

No, V1 is still supported. It's just that you're missing out on some optimizations.

How would I do it?

You can either follow the instructions in option 1 or check out what changed yourself by following the steps in option 2.

Option 1: Minimal path to V2

  • Go to the source code of your custom widget

  • Install latest version of @ichicraft/widgets-widget-base dependency, this adds support for new properties manifestVersion and externals to the manifest.config.ts file.

  • Update config\manifest.config.ts

    • Add key-value manifestVersion: 2 to configuration, this tells the Widget Board to use new loader with support for externals.
    • (optional but recommended) Add property externals to configuration and point dependencies to CDN module location.
  • About the new externals property

    • Use intellisense to see how the property can be defined or see example below
    • Try to use the same versions and CDN locations across different widgets to get the most out of 'dependency sharing'
    • Use AMD, UMD or global modules. ES6 modules are not yet supported

Ichicraft out-of-the-box widgets currently use the following externals. This is also the default configuration for new widgets scaffolded by our Yeoman generator:

    externals: {
        react: {
            path: 'https://cdn.jsdelivr.net/npm/[email protected]/umd/react.production.min.js',
        },
        'react-dom': {
            path: 'https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.production.min.js',
            dependencyMappings: {
                react: 'react',
            },
        },
        '@fluentui/react': {
            path: 'https://cdn.jsdelivr.net/npm/@fluentui/[email protected]/dist/fluentui-react.umd.js',
            dependencyMappings: {
                React: 'react',
                ReactDOM: 'react-dom',
            },
        },
        i18next: {
            path: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/i18next.min.js',
        },
        'react-i18next': {
            path: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/amd/react-i18next.min.js',
            dependencyMappings: {
                react: 'react',
            },
        },
    }
  • Make sure you've got the correct versions in your package.json. For the externals mentioned above this results in the following:
        "@fluentui/react": "8.34.2",
        "i18next": "20.6.1",
        "react": "16.8.6",
        "react-dom": "16.8.6",
        "react-i18next": "11.12.0",
  • Note that @fluentui/react is now used in the aforementioned externals and package.json. This is version 8 of the React component library of Fluent UI (fka UI Fabric), replacing office-ui-fabric-react. If you're using Fluent UI too, we recommend upgrading to version 8 and 'share' the externalized @fluentui/react we also use for Ichicraft built-in widgets. To read more about migrating from Fluent UI 7 to 8, go to Fluent UI Migration guide.

To make sure the Fluent UI React library (or parts thereof) isn't bundled together with the package, it's important to import components from the root of the library. So don't use deep-references because this would cause Webpack to include the library in the bundle:

// Good
import { Icon, Stack, StackItem } from '@fluentui/react';

// Bad
import { Icon } from '@fluentui/react/lib/Icon';
import { Stack, StackItem } from '@fluentui/react/lib/Stack';
  • Update webpack.common.ts and replace the output.library and output.libraryTarget properties with this:
    library: `widget_${manifestConfig.id.replace(/-/g, '_')}`,
    libraryTarget: 'amd',
  • Update webpack.common.ts (or webpack.prod.ts if you only want to load externals in production builds) by inserting the following block at the bottom of the file, right above export default config:
// Keep some of the dependencies out of the bundle, as defined in the manifest config
// These will be loaded by the Widget Board solution
config.externals = {};
Object.keys(manifestConfig.externals)?.forEach((e) => {
    config.externals[e] = e;
});
  • To test your new widget using the new externals, run npm run start. (Reminder: make sure you updated webpack.common.ts so you can test loading files from the CDN in dev-mode too.)
  • Now build the widget and deploy it using the newly generated manifest.json file.

Option 2: Manually compare

  • Download the latest version of the Yeoman widget generator (v 1.3.0)
  • Create a new widget using the generator, this will automatically be a 'V2' widget
  • Compare this to your V1 widget and see what's new/updated