sharepoint-onlineweb-partsmyst

How to use myst-parser for SharePoint web part?


I tried to include myst-parser as external JavaScript library for a SharePoint WebPart, following

https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/use-existing-javascript-libraries#reference-existing-libraries-as-external-resources

  "externals": {
    "myst-parser": {
      "path": "https://cdn.jsdelivr.net/npm/myst-parser@1.0.21/dist/myst.min.js",
      "globalName": "myst-parser"
    }
  },

In my webpart:

import * as myst from 'myst-parser';
const html = myst.mystParse('# Hello to the world!')

I am able to server the web part. However, it shows

enter image description here

=> How to correctly include myst-parser in Sharepoint?

Related:

https://github.com/executablebooks/mystmd/issues/824#issuecomment-1880858355

How to use unified.js in sharepoint web part?


Solution

  • I hade to downgrade the version of unified and adapt gulpfile.js to include a custom webpack configuration.

    Content of package.json:

    {
      "name": "component-webpart",
      "version": "0.0.1",
      "private": true,
      "engines": {
        "node": ">=16.13.0 <17.0.0 || >=18.17.1 <19.0.0"
      },
      "main": "lib/index.js",
      "scripts": {
        "build": "gulp bundle",
        "clean": "gulp clean",
        "test": "gulp test"
      },
      "dependencies": {
        "@fluentui/react": "^8.106.4",
        "@microsoft/sp-component-base": "1.18.2",
        "@microsoft/sp-core-library": "1.18.2",
        "@microsoft/sp-lodash-subset": "1.18.2",
        "@microsoft/sp-office-ui-fabric-core": "1.18.2",
        "@microsoft/sp-property-pane": "1.18.2",
        "@microsoft/sp-webpart-base": "1.18.2",
        "@pnp/spfx-property-controls": "3.15.1",
        "@pnp/telemetry-js": "2.0.0",
        "devlop": "1.1.0",
        "marked": "11.1.0",
        "myst-parser": "1.0.21",
        "myst-to-html": "1.0.21",
        "react": "17.0.1",
        "react-dom": "17.0.1",
        "rehype-stringify": "9.0.3",
        "tslib": "2.3.1",
        "unified": "10.0.1" 
      },
      "devDependencies": {
        "@microsoft/eslint-config-spfx": "1.18.2",
        "@microsoft/eslint-plugin-spfx": "1.18.2",
        "@microsoft/rush-stack-compiler-4.7": "0.1.0",
        "@microsoft/sp-build-web": "1.18.2",
        "@microsoft/sp-module-interfaces": "1.18.2",
        "@rushstack/eslint-config": "2.5.1",
        "@types/marked": "^6.0.0",
        "@types/node": "^20.11.5",
        "@types/react": "17.0.45",
        "@types/react-dom": "17.0.17",
        "@types/unist": "3.0.2",
        "@types/webpack-env": "1.18.4",
        "ajv": "^6.12.5",
        "eslint": "8.7.0",
        "eslint-plugin-react-hooks": "4.3.0",
        "gulp": "4.0.2",
        "typescript": "5.3.3",
        "webpack": "5.89.0"
      }
    }
    

    Content of gulpfile.js:

    'use strict';
    
    const build = require('@microsoft/sp-build-web');
    
    
    build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
    
    var getTasks = build.rig.getTasks;
    build.rig.getTasks = function () {
      var result = getTasks.call(build.rig);
    
      result.set('serve', result.get('serve-deprecated'));
    
      return result;
    };
    
    
    build.configureWebpack.mergeConfig({
      additionalConfiguration: (generatedConfiguration) => {
        generatedConfiguration.module.rules.push(
          {
            resolve: {
              alias: {   
                'myst-parser': 'myst-parser/dist',                      
                'myst-common': 'myst-common/dist',
                'myst-directives': 'myst-directives/dist',
                'myst-frontmatter': 'myst-frontmatter/dist',
                'myst-roles': 'myst-roles/dist',
                'myst-spec': 'myst-spec/dist',
                'myst-spec-ext': 'myst-spec-ext/dist',
                'myst-to-html': 'myst-to-html/dist',
                'myst-transforms': 'myst-transforms/dist',
                'markdown-it-amsmath': 'markdown-it-amsmath/dist',           
                'markdown-it-dollarmath': 'markdown-it-dollarmath/dist',           
                'markdown-it-myst': 'markdown-it-myst/dist',
                'markdown-it-myst-extras': 'markdown-it-myst-extras/dist',   
              },
            },
          }
        );
    
        return generatedConfiguration;
      }
    });
    
    build.initialize(require('gulp'));
    

    Example usage:

    import {unified} from 'unified';
    import { mystParser } from 'myst-parser';
    import { State, transform, mystToHast, formatHtml  } from 'myst-to-html';
    import rehypeStringify from 'rehype-stringify';
    
    //...
    
    let htmlString = '!! Could not render markdown content with MyST !!:\n' + markdownContent;
    
      try{
        const pipe = unified()
        .use(mystParser)
        .use(transform, new State())     
        .use(mystToHast)
        .use(formatHtml)
        .use(rehypeStringify);
    
        const result = pipe.processSync(markdownContentWithLinks);
        htmlString = result.value;   
      } catch(error){
        console.log('Could not render markdown content with MyST!', error);
      }    
    
      return (   
        <div 
          className={styles.component}
          title={extraSearchTerms}       
          data-source={url} 
        >   
        <div
         dangerouslySetInnerHTML={{__html:htmlString}}
        >
        </div>      
        </div>      
      );