SAP-samples / ui5-typescript-tutorial

Tutorial for building UI5 applications with TypeScript.

Home Page:https://sap.github.io/ui5-typescript/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`ModuleError: Failed to resolve dependencies` (`npm`, `zod`)

sz3lbi opened this issue · comments

Hi,
I want to use zod along with the UI5. Therefore, I tried to go with the exercise 4.
What steps have I done?

  1. Installed zod: npm install zod --save-dev (also tried as a normal dependency, not a dev one, but no difference).
  2. Installed ui5-tooling-modules: npm install ui5-tooling-modules --save-dev
  3. Edited the ui5.yaml as described in the exercise (full contents of the file below).
  4. Imported zod into a TypeScript file.
  5. Started the project with npm run start.

devDependencies in package.json:

"devDependencies": {
  "@babel/eslint-parser": "7.14.7",
  "@sap-ux/eslint-plugin-fiori-tools": "^0.2.0",
  "@sap-ux/ui5-middleware-fe-mockserver": "2",
  "@sap/ux-ui5-tooling": "1",
  "@sapui5/ts-types-esm": "~1.108.22",
  "@typescript-eslint/eslint-plugin": "^5.59.0",
  "@typescript-eslint/parser": "^5.59.0",
  "@ui5/cli": "^3.0.0",
  "eslint": "7.32.0",
  "eslint-plugin-fiori-custom": "2.6.7",
  "typescript": "^5.1.6",
  "ui5-tooling-modules": "^3.0.7",
  "ui5-tooling-transpile": "^3.2.0",
  "zod": "^3.22.2"
},

ui5.yaml:

# yaml-language-server: $schema=https://sap.github.io/ui5-tooling/schema/ui5.yaml.json

specVersion: "3.1"
metadata:
  name: XXX
type: application
server:
  customMiddleware:
    - name: ui5-tooling-modules-middleware
      afterMiddleware: compression
    - name: fiori-tools-proxy
      afterMiddleware: compression
      configuration:
        ignoreCertError: true # If set to true, certificate errors will be ignored. E.g. self-signed certificates will be accepted
        ui5:
          path:
            - /resources
            - /test-resources
          url: https://ui5.sap.com
        backend:
          - path: /sap
            url: XXX
            client: "XXX"
            destination: XXX
    - name: fiori-tools-appreload
      afterMiddleware: compression
      configuration:
        port: 35729
        path: webapp
        delay: 300
    - name: ui5-tooling-transpile-middleware
      afterMiddleware: compression
      configuration:
        debug: true
        excludePatterns:
          - /Component-preload.js
    - name: fiori-tools-preview
      afterMiddleware: fiori-tools-appreload
      configuration:
        component: XXX
        ui5Theme: sap_horizon
builder:
  customTasks:
    - name: ui5-tooling-modules-task
      afterTask: replaceVersion
      configuration:
        addToNamespace: true
    - name: ui5-tooling-transpile-task
      afterTask: replaceVersion
      configuration:
        debug: true

zod usage:

import { z } from "zod";

export const oCommiAreas = z.object({
  Area: z.string().max(30),
  Arbpl: z.string().max(8),
  AreaDescr: z.string().max(40),
  Target: z.number().int(),
});

export type CommiAreas = z.infer<typeof oCommiAreas>;

I get the following error in the browser's Dev Tools:
Uncaught (in promise) ModuleError: Failed to resolve dependencies of '.../controller/MainView.controller.js'
ModuleError

The sources of the page in the Dev Tools look like this. There is no zod.js file anywhere.
image

According to zod.dev, zod has "zero dependencies" and "works in Node.js and all modern browsers".
Could you please help me with this issue?

What I've tried:

  1. Changing the order of entries and value of the afterMiddleware parameters as described here: #12 (comment)
  2. Changing the value of the specVersion parameter.
  3. Add UI5 dependencies to package.json.
  4. Start the application in SAP BAS and VSCode with SAP Fiori extensions.

In the .babelrc.json file, I see some settings related to UI5 transformations. Is it possible that this also needs some customization?

{
    "presets": [
        "@babel/preset-env",
        [
            "transform-ui5",
            {
                "overridesToOverride": true
            }
        ],
        "@babel/preset-typescript"
    ],
    "plugins": [
        "transform-remove-console",
        [
            "transform-async-to-promises",
            {
                "inlineHelpers": true
            }
        ]
    ],
    "sourceMaps": true
}

@petermuessig is the creator of ui5-tooling-modules, but as a first check: when you do npm run build, does zod then show up in the dist folder below "thirdparty"?

What I did (with some success):

Result 1: zod is present in the build results (and should also be available at runtime in the dev server, albeit not visible in the dev tools when not loaded)

Result 2: there is still an error in the console when I do npm run start:dist, but it looks slightly different: zod.js is loaded and executed but fails:
image

Result 3: in the build log there is an error, but not sure from where and how relevant it is, as zod IS present:

info com.myorg.myapp › Running task generateComponentPreload...
error lbt:analyzer:JSModuleAnalyzer Unhandled AST node type MetaProperty Node {
  type: 'MetaProperty',
  start: 2555,
  end: 2565,
  meta: Node { type: 'Identifier', start: 2555, end: 2558, name: 'new' },
  property: Node { type: 'Identifier', start: 2559, end: 2565, name: 'target' }
}
error lbt:resources:ResourcePool Failed to analyze com/myorg/myapp/thirdparty/zod.js: Unhandled AST node type MetaProperty
info ProjectBuilder Build succeeded in 1.05 s
info ProjectBuilder Executing cleanup tasks..

Not sure whether error 2 results from error 3. @petermuessig : any idea?

@akudev, when I build, zod is present in the build results and visible in the Dev Tools. I get an error in the console, but a little different. It's pretty similar though.
image

There is no content on the page at all (and there should be).
I also get an error in the terminal:

error lbt:analyzer:LibraryJS Unexpected property 'customElements' or wrong type for 'customElements' for a library initialization call in '/resources/sap/ui/integration/library.js'

The exact problems I described in the first post occur when I run the project with the following script:
"start": "fiori run --open \"test/flpSandbox.html?sap-client=100&sap-ui-xx-viewCache=false#XXX-display\"",

Now I'm thinking that maybe I should have created this issue in a repository of the extension instead of doing it here...

I'll prepare a solution, the problem is that the zod already exposes the __esModule property to its exports and we try to redefine it to mark the module as former esModule and this leads to an error... We need to try..catch the redefine of the marker...

Please try with ui5-tooling-modules version 3.0.8

When I run the app as @akudev described, by building it first and then running it from the dist directory, it works fine.

Unfortunately, if I just run it with the default start script (fiori run --open \"test/flpSandbox.html?sap-client=100&sap-ui-xx-viewCache=false#XXX-display\"), I still get the error described in the first post of this discussion. Changing it to ui5 serve --port 8080 -o index.html (copied from https://github.com/SAP-samples/ui5-typescript-tutorial/blob/main/exercises/ex4/com.myorg.myapp/package.json) doesn't help either.
Is this the intended behavior? Building the app takes quite a long time, I have to do it manually every time instead of relying on the auto reload, and it also removes all debugger statements placed in the code, so it's not very convenient.

Trying the first point from my comment helps here.
However, this is not how the configuration is described in the exercise: https://github.com/SAP-samples/ui5-typescript-tutorial/tree/main/exercises/ex4#exercise-41---installconfigure-ui5-tooling-extensions

server:
  customMiddleware:
    - name: fiori-tools-proxy
      afterMiddleware: compression
      configuration:
        ignoreCertError: false # If set to true, certificate errors will be ignored. E.g. self-signed certificates will be accepted
        ui5:
          path:
            - /resources
            - /test-resources
          url: https://ui5.sap.com
        backend:
          - path: /sap
            url: http://e01-pripro:443
            client: '100'
            destination: E01_100
    - name: fiori-tools-appreload
      afterMiddleware: compression
      configuration:
        port: 35729
        path: webapp
        delay: 300
    - name: ui5-tooling-transpile-middleware
      afterMiddleware: compression
      configuration:
        debug: true
        excludePatterns:
          - /Component-preload.js
    - name: fiori-tools-preview
      afterMiddleware: fiori-tools-appreload
      configuration:
        component: XXX
        ui5Theme: sap_horizon
    - name: ui5-tooling-modules-middleware
      afterMiddleware: ui5-tooling-transpile-middleware

@akudev @petermuessig Thanks a lot for your help :)

@sz3lbi - please take a look into the following explanation in the tutorial:
https://github.com/SAP-samples/ui5-typescript-tutorial/tree/main/exercises/ex4#exercise-42---addingtesting-the-npm-package-nominatim_client

When loading UI5 from a CDN, then this collides with the local resources and for all local resources you need to maintain the resourceroots in the HTML page - in your case in the test/flpSandbox.html. You need to define a local path mapping for your thirdparty to ensure that it is loaded via the ui5-tooling-modules middleware extension.

HTH

In other words: your yaml contains this section

        ui5:
          path:
            - /resources
            - /test-resources
          url: https://ui5.sap.com

which causes the UI5 tooling to load everything below the path /resources from ui5.sap.com. But of course zod does not exist there. Hence the suggestion from @petermuessig to set the data-sap-ui-resourceroots to load zod from somewhere else.

BUT: this is a client-side setting and simply setting something like

data-sap-ui-resourceroots='{
		"com.myorg.myapp": "./",
		"zod": "./resources/zod"
	}'

or so will probably not work, because the path requested from the (UI5) server is still /resources/.... Or am I wrong? Hence one would have to choose a different beginning of the path and also configure something in the yaml for this prefix.

Or simply get rid of the setting with the UI5 URL in the yaml.

That works if you ensure from the order of the middlewares that the ui5-tooling-modules runs before the fiori-tools-proxy - therefore you can use the beforeMiddleware and afterMiddleware config