Hi, all,
With this blogpost I would like to document the steps that I went through in order to obtain a clean starting CAP project setup using TypeScript.
Below I will go through a series of terminal commands and some file configuration.
It might take quite some time to go through all the steps the first time around.
But once finished, you can easily copy-paste this config to your different projects.
This whole process should ideally be included into one big Yeoman generator, but for now this is how I do it manually.
Feel free to comment for any suggestions or variations on this. I'm curious to learn about the best approach myself.
Advantages / features of the this current setup:
- CAP project is using TypeScript
- Custom Fiori project is using TypeScript
- Breakpoints get triggered in BAS in the CAP TypeScript files
- Fiori TypeScript files can be viewed in the browser console for debugging
- Live reload when updating the Fiori project
Initializing the CAP-side of the project
Getting started
Let's get started with some initial files by running the "cds init" command.
(Make sure to do this within a previously created project folder)
cds init
Converting CAP project to TypeScript
Use the following commands to install TypeScript locally in our project and to add the TypeScript dependencies.
npm install --save-dev typescript
npm i -g typescript ts-node
npm i --save-dev @types/node
Now we can add a new file "tsconfig.json to our rootdir. To finalize our TypeScript setup.
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./gen/srv/srv",
"rootDir": "./srv",
"baseUrl": "./",
"moduleResolution": "node",
"skipLibCheck": true,
"preserveConstEnums": true,
"sourceMap": false,
"allowJs": true,
"strict": true,
"strictNullChecks": false,
"strictPropertyInitialization": false,
"esModuleInterop": true
},
"include": [
"./srv/**/*"
]
}
Our project is now TypeScript ready, but it isn't doing anything yet so let's create a quick test service and function.
/srv/warehouse.cds
service warehouse {
//warehouse/hello(to='world')
function hello (to:String) returns String;
}
/srv/warehouse.ts
import { Service } from "@sap/cds/apis/services";
module.exports = (warehouse: Service)=>{
warehouse.on ('hello', req => {
return `Hello ${req.data.to} `
})
}
At this point you could already do a first CAP test, see if the TypeScript version is working with the follwing commands
Make sure everything is installed:
npm i
Run the project:
cds-ts watch
We can test our first function by going to the endpoint:
...localhost:4004/service/warehouse/hello(to='world')
But if we want our breakpoints to work in BAS, the easiest way is to run cap via a debug configuration file.
To do so, add the config below to the list of "configurations"
in the launch file.
/.vscode/launch.json
{
"command": "cds-ts run --with-mocks --in-memory?",
"name": "cds-ts run",
"request": "launch",
"type": "node-terminal",
"skipFiles": [
"<node_internals>/**"
],
"sourceMaps": true,
"disableNetworkCache": true,
"showAsyncStacks": true
}
Great, we are done on the CAP side of things for now.
Initializing the Fiori project
So we have our CAP back-end but now we want to generate a custom Fiori front-end on top of this. We could simply use the Wizard, but this doesn't offer any TypeScript options for now. So we are going to do it with
Yeoman terminal commands instead.
Installing the necessary tools:
Go to the app folder of your current project and run the following commands:
npm install -g yo generator-easy-ui5
Note: The command above installs Yeoman andthe eay-ui5 generator globally. You don't need to repeat these steps each time if you installed these tools previously.
You can check whether or not the tools are installed by running "yo --generators".
If everything is installed correctly it will display a list of available generators.
Now let's start the actual Fiori project:
yo easy-ui5 ts-app
The Yeoman terminal wizard will be appear prompting you with some question for the creation of your project.
Be careful, if you choose to use capital letters in your namespace or application name.
This by itself is fine, but you will have to change them to lower case manually in the
ui5.yaml file later.
Also notice that I didn't opt for a git repository.
I decided to use one big Git repository for the whole CAP project (including the app folder and thus also this Fiori sub-project.)
ui5.yaml
make sure that this is all lowercase as mentioned previously:
At this point we have a working Fiori project that can be executed with:
npm run start
Quick UI5 code-snippet so we can test our app.
I added a button to my Fiori app in order to test the CAP function that we created previously.
If you want to follow along with the same test function you can copy this setup:
Main.view.xml
added:
<Button text="CAP test TVC" press="callCap" />
Main.controller.ts
added:
//Simple Function call to CAP
public async callCap() {
const oContext = this.getOwnerComponent().getModel().bindContext("/hello(...)");
oContext.setParameter("to", "test");
await oContext.execute();
let result = oContext.getBoundContext().getObject() as capFunctionResult;
console.log(result);
MessageBox.show(result.value);
}
The final part bellow will connect both apps.
We want to call our CAP function from within the Fiori and get the response from our request.
Connecting Fiori to CAP
There is no connection yet to the CAP backend though.
To fix this, we need to:
Add the following files
/app/services.cds
using from './yourFioriProjectFolder/annotations';
/app/yourFioriProjectFolder/services.cds
using warehouse as service from '../../srv/warehouse';
Update the manifest
/app/yourFioriProjectFolder/webapp/manifest.json
Under "sap.app": ==> datasource
"dataSources": {
"mainService": {
"uri": "/warehouse/",
"type": "OData",
"settings": {
"annotations": [],
"localUri": "localService/metadata.xml",
"odataVersion": "4.0"
}
}
}
Under "sap.ui5" --> "models" ==> datasource new model
"": {
"dataSource": "mainService",
"preload": true,
"settings": {
"synchronizationMode": "None",
"operationMode": "Server",
"autoExpandSelect": true,
"earlyRequests": true
}
}
But running our app at this point would give us a connection error
Fixing this local connection can be done with the fiori-tools-proxy
The command for Installing the dependency:
npm install @sap/ux-ui5-tooling --save-dev
Adding the configuration for this tooling:
/app/yourFioriProjectFolder/ui5.yaml
Under
server ==> customMiddleware:
- name: fiori-tools-proxy
afterMiddleware: compression
configuration:
backend:
- path: /warehouse
url: http://localhost:4004
Running the final app:
We can now run the entire app but we still need to execute 2 different bash commands in 2 different instances.
- The CAP part
- Run the cap project via the debugger “play button”
- The Fiori app
- Via the command “npm run start” within the Fiori project folder.
If you run into this error while executing the app:
Update the index.html
index.html
Live reload when updating the Fiori project
The live reload settings below assume that your transpiled JavaScript files reside in the "
webapp" folder.
But In our current setup we already have the TypeScript files in that directory
Therefore
rename your “
webapp” folder to “
src”.
A new folder called "webapp" will be generated again once we run our TypeScript transpiler.
package.json (from the Fiori app)
replace
"start": "ui5 serve --port 8080 -o index.html",
with
"start": "npm-run-all --parallel watch:ts start:ui5",
"watch:ts": "babel webapp --out-dir webapp --source-maps true --extensions \".ts,.js\" --copy-files --watch",
"start:ui5": "ui5 serve --port 8081 -o index.html",
(I renamed the original start to “start_old” as backup in case I ever need it again)
still in the same file, we need will need to declare our additional dependencies Don’t copy them manually though, we can use the npm commands mentioned below in order to get the latest up-to-date versions:
something like this will be added to the package.json:
"@babel/cli": "^7.16.8",
"@babel/core": "^7.16.7",
"@babel/preset-env": "^7.16.8",
"@babel/preset-typescript": "^7.16.7"
"npm-run-all": "^4.1.5",
The npm commands to add these last dependencies:
npm install --save-dev @babel/cli @babel/core @babel/preset-env @babel/preset-typescript
npm install npm-run-all --save-dev
A last step, almost done
🙂
ui.yaml
configure the live reloading in the yaml file by adding the following config under
server ==> customMiddleware:
- name: fiori-tools-appreload
afterMiddleware: compression
configuration:
port: 35729
path: webapp
And finished!
Your Fiori project should automatically refresh with every change you make.
I'm still investigating options to run it all with one single command.
At this point we still need to terminal instances.
But we should have the following features as promised:
- CAP project is using TypeScript
- Custom Fiori project is using TypeScript
- Breakpoints get triggered in BAS in the CAP TypeScript files
- Fiori TypeScript files can be viewed in the browser console for debugging
- Live reload when updating the Fiori project