Forum Discussion

Kiril Iliev's avatar
Kiril Iliev
Copper Contributor
Jul 29, 2025

SPFX 1.21.1 in monorepo - utility module could not be exported

I am trying to migrate multiple projects to monorepo. I need to migrate some common utilities functions in a common module.

There is an export warning that the module has no exports, while it does has.

Running npm run spfx1:build works fine. But when I do npm run spfx1:serve it throws a warning 

export 'DemoUtilities' (imported as 'DemoUtilities') was not found in 'utilities-library/utils' (module has no exports)

Opening the a SharePoint page online, it errors with missing exports.

 

Can you point me to possible solutions?

 

Here is a very simple OOB SPFX solution structure:

 

utilities-library

- src 

-- utils.ts

- index.ts

- package.json

- tsconfig.json

spfx1

- config

- sharepoint

- src

-- skipped for brevity

- gulpfile.js

- package.json

- tsconfig.json

package.json

tsconfig.base.json

 

Specifics for per files

utilities-library -> package.json

{
    "name": "utilities-library",
    "version": "1.0.0",
    "main": "lib/index.js",
    "types": "lib/index.d.ts",
    "scripts": {
        "start": "node index.js",
        "test": "echo \"test\""
    },
    "type": "module",
    "workspaces": [
        "true"
    ],
    "devDependencies": {
        "typescript": "^5.3.5"
    }
}

utilities-library ->tsconfig.json

{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "outDir": "lib"
  },
  "include": ["**/*.ts"]
}

utilities-library ->index.ts

export { DemoUtilites } from './src/utils';

utilities-library -> utils.ts

import { ISPFXContext, spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";

export const DemoUtilites = {
  checkListExists: async (
    listTitle: string,
    context: ISPFXContext
  ): Promise<boolean> => {
    const sp = spfi().using(SPFx(context));
    return new Promise<boolean>((resolve) => {
      sp.web.lists
        .getByTitle(listTitle)()
        .then(() => {
          resolve(true);
        })
        .catch((error) => {
          if (!(error?.status === 404)) {
            console.log(`Error checking list ${listTitle}`, error);
          }
          resolve(false);
        });
    });
  }
}

spfx1 -> gulpfile.js

'use strict';

const build = require('@microsoft/sp-build-web');
const path = require("path");

build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);

build.configureWebpack.mergeConfig({
  additionalConfiguration: (generatedConfig) => {
    generatedConfig.resolve = generatedConfig.resolve || {};
    generatedConfig.resolve.alias = {
      ...(generatedConfig.resolve.alias || {}),
      'utilities-library': path.resolve(__dirname, '../utilities-library/lib'),
      'utilities-library/utils': path.resolve(__dirname, '../utilities-library/lib/utils')
    };
    return generatedConfig;
  }
});

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.initialize(require('gulp'));

spfx1 -> package.json

{
...
"dependencies": {
    "@microsoft/decorators": "1.21.1",
    "@microsoft/sp-core-library": "1.21.1",
    "@microsoft/sp-dialog": "1.21.1",
    "@microsoft/sp-listview-extensibility": "1.21.1",
    "@pnp/sp": "^4.12.0",
    "utilities-library": "^1.0.0",
    "office-ui-fabric-react": "^7.204.1",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "tslib": "2.3.1"
  },
...
}

spfx1 -> tsconfig.json

{
  "extends": "../tsconfig.base.json",
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "lib"
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "references": [
    { "path": "../utilities-library" }
  ]
}

root -> package.json

{
  "name": "monorepo-test",
  "workspaces": [
    "spfx1",
    "utilities-library"
  ],
  "scripts": {
    "spfx1:build": "gulp build -f ./spfx1/gulpfile.js --workspace spfx1",
    "spfx1:clean": "gulp clean -f ./spfx1/gulpfile.js --workspace spfx1",
    "spfx1:serve": "gulp serve -f ./spfx1/gulpfile.js --workspace spfx1 --nobrowser",
    "spfx1:bundle": "gulp bundle -f ./spfx1/gulpfile.js --workspace spfx1",
    "spfx1:pkg": "gulp package-solution -f ./spfx1/gulpfile.js --workspace spfx1",
    "spfx1:prod": "gulp build -f ./spfx1/gulpfile.js --workspace spfx1 --ship & gulp bundle -f ./spfx1/gulpfile.js --workspace spfx1 --ship & gulp package-solution -f ./spfx1/gulpfile.js --workspace spfx1 --ship",

    "utilities-library:build": "tsc --project utilities-library/tsconfig.json",
    "utilities-library:watch": "npm run utilities-library:build -- --watch",
    "clean:node": "rm -rf **/node_modules"
  },
  "devDependencies": {
    "npm-run-all": "^4.1.5"
  }
}

root -> tsconfig.base.json

{
  "extends": "./node_modules/@microsoft/rush-stack-compiler-5.3/includes/tsconfig-web.json",
  "compilerOptions": {
    "target": "es5",
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "react",
    "declaration": true,
    "sourceMap": true,
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "outDir": "lib",
    "inlineSources": false,
    "noImplicitAny": true,
    "rootDir": ".",
    "baseUrl": ".",  // Important for path mapping
    "paths": {
      "utilities-library/*": [
        "utilities-library/lib/*"
      ]
    },
    "typeRoots": [
      "./node_modules/@types",
      "./node_modules/@microsoft"
    ],
    "types": [
      "webpack-env"
    ],
    "lib": [
      "es5",
      "dom",
      "es2015.collection",
      "es2015.promise"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx"
  ]
}

 

2 Replies

  • Kiril Iliev's avatar
    Kiril Iliev
    Copper Contributor

    Fixed it by doing the following:

    1. Added module in the library -> tsconfig

    { "compilerOptions": { ... "module": "ESNext" }, ... }

    1. Added module and target in spfx1 -> tsconfig

    { "extends": "../tsconfig.base.json", "compilerOptions": { ... "module": "ESNext", "target": "esnext" }, ... }

    1. Updated strictNullChecks in the root tsconfig.base.json to false as it was not compatible with scaffolded projects very well when using FluentUI.
  • Martynow's avatar
    Martynow
    Iron Contributor

    Upgrade SPFx to the latest version, check for dependency conflicts in node_modules, and ensure the utility,moduleis correctly referenced in package.json.

Resources