Blog
All Blog Posts | Next Post | Previous PostCompiling TMS WEB Core Projects with the DCC
Thursday, April 21, 2022
1. Introduction
TMS WEB Core is a framework that allows the user to write JavaScript applications with the Pascal language. Therefore the Pascal code is transpiled to JavaScript.
TMS WEB Core supports the three IDEs Embarcadero RAD Studio with Delphi, Microsoft Visual Studio Code and Lazarus.
This article is primarily concerned with the Delphi IDE and shows how to use hidden features to accelerate the work with the IDE.
2. Pas2JS Transpiler
TMS WEB Core uses the Pas2JS transpiler in order to convert the Pascal code to JavaScript. In the following the transpiler is abbreviated with Pas2JS.
Pas2JS is basically compatible with the Delphi language, but there are exceptions. Because of these exceptions the Delphi IDE sometimes does not work correctly with some basic features like Code Insight.
2.1. Code Insight
Code Insight is a feature of the Delphi IDE that helps the user to write his code faster. Code Insight includes Code Completion, Parameter Completion, Code Hints, Tooltip Expression, Tooltip Insight, Go To Definition, Block Completion, Class Completion and Error Insight. It can only work if the current project is a Pascal project that can be compiled with the Delphi Compiler.
2.2. Delphi Compiler
The Delphi Compiler is the so called DCC (Delphi Commandline Compiler) which normally compiles Delphi projects. In case of a TMS WEB Core project things are different. A TMS WEB Core project is compiled with Pas2JS, not with the DCC. This behavior has consequences for Code Insight, which only works for projects that can be and are compiled with the DCC.
2.3. Compiling WEB Core projects with the DCC
TMS WEB Core has a wonderful hidden feature that allows the user to compile WEB Core projects additionally with the DCC. This feature can be enabled in Tools\Options\TMS WEB\Options.
If Show the DCC button is set to True a tool button will appear in the tool bar, which allows to toggle between the DCC and Pas2JS.
Here, Pas2JS is enabled. A compiled project looks like the following:
And here the DCC is enabled:
If the project is compiled with the DCC, code completion looks like this:
2.4. Compilation Speed
Since the DCC is one of the fastest compilers in the world, it compiles much faster than Pas2JS. Hence it is a good practice to compile a WEB Core project with the DCC during coding. The user can always check with a click on Ctrl+F9 whether his code is compilable.
3. Special Language Features
Pas2JS introduces a few special language features that cannot be compiled directly with the DCC. In the following it will be shown how they can be written in a DCC compatible way.
3.1. ASM
Pas2JS allows to write plain JavaScript in so called ASM blocks. Here is an example:
class function TIntegerHelper.ToString(const AValue: Integer): string; assembler;
asm
return AValue.toString();
end;
With the help of the internal compiler defines WEBLIB and PAS2JS you can write this code in the following way:
class function TIntegerHelper.ToString(const AValue: Integer): string;
begin
{$IFDEF WEBLIB}
asm
return AValue.toString();
end;
{$ELSE}
Result := IntToStr(AValue);
{$ENDIF}
end;
This code now compiles and works with the DCC and Pas2JS.
3.2. WEBLib.Utils
The counterpart of many utility functions from Delphis System.SysUtils unit are currently defined in the Pas2JS unit WEBLib.Utils. With the upcoming version 2.2 of Pas2JS they will be moved to SysUtils. That is why it is currently necessary to use WEBLib.Utils.
uses
WEBLib.Utils;
procedure TForm1.WebButton1Click(Sender: TObject);
begin
ShowMessage(DateToStr(Now, FormatSettings));
end;
3.3. Namespaces
Although Pas2JS does not know the System namespace, it is allowed to use it:
uses
System.SysUtils;
This is a valid uses clause for Pas2JS and the DCC. The same can be done with the Vcl:
uses
Vcl.Forms;
The supported namespaces are
- Data
- Datasnap
- System
- Vcl
3.4. Await
JavaScript applications may be asynchronous. Therefore Pas2JS supports the Await keyword. The whole mechanism is explained in this article.
The best way to write asynchronous functions in a DCC compatible way is to use the Async attribute and the generic TAwait record.
[async] procedure MyFunction;
var
lValue: Boolean;
begin
lValue := TAwait.Exec<Boolean>(AsyncFunction);
end;
Now the asynchronous code is fine with the DCC.
4. Summary
I hope this article helps to write Pas2JS code in a Delphi compatible way so that all IDE features like Code Insight can be used. The other huge advantage is that the DCC is much faster than Pas2JS, which helps to reduce the so called turnaround times.
A last remark is that in this case the well known and often used IDE plugin ModelMaker Code Explorer also works.
Masiha Zemarai
This blog post has received 11 comments.
2. Friday, April 22, 2022 at 12:32:28 PM
Hi Masiha,
Thanks for the post but when I use DCC for current projects I get a lot of compiler (more that 100 in just one project) errors. It seems that this flag should be switched on when starting from zero as it is very time consuming and not practical to satisfy DCC after progressing on the project.
Thanks for the post but when I use DCC for current projects I get a lot of compiler (more that 100 in just one project) errors. It seems that this flag should be switched on when starting from zero as it is very time consuming and not practical to satisfy DCC after progressing on the project.
Borbor Mehmet Emin
3. Friday, April 22, 2022 at 6:41:27 PM
Hi Borbor,
how do the compiler errors look like? Does CodeInsight currently work for you?
how do the compiler errors look like? Does CodeInsight currently work for you?
Roman Kassebaum
4. Monday, April 25, 2022 at 7:23:28 AM
Hi Roman,
Half of the errors are due to await keyword (they are not DCC compatible) and rest are typecasting errors.
Half of the errors are due to await keyword (they are not DCC compatible) and rest are typecasting errors.
Borbor Mehmet Emin
5. Monday, April 25, 2022 at 12:15:22 PM
There must be more to this as I cannot see this here, for example in the demo Demo\Basics\MultiForm where I could not see a code insight problem while await() is used.
Do you have more details how we can reproduce this?
Do you have more details how we can reproduce this?
Bruno Fierens
6. Monday, April 25, 2022 at 1:52:59 PM
Hi Borbor,
as described under "3.4. Await" replace all "async" keywords with the attribute "[Async]" and use "TAwait.Exec<>" instead of "await". This approach is BTW compatible to the MMX.
Do you have an example for such a typecast?
as described under "3.4. Await" replace all "async" keywords with the attribute "[Async]" and use "TAwait.Exec<>" instead of "await". This approach is BTW compatible to the MMX.
Do you have an example for such a typecast?
Roman Kassebaum
7. Monday, April 25, 2022 at 4:47:53 PM
Hi Bruno,
Response := Await(XDataWebClient.RawInvokeAsync(''IUserAccountsService.Signin'', [AUsername, APassword]));
[dcc32 Error] MainModule.pas(143): E2010 Incompatible types: ''TXDataClientResponse'' and ''TJSValue''
if I code it like this there is no more complains by DCC:
Response := TAwait.Exec<TXDataClientResponse>(XDataWebClient.RawInvokeAsync(''IUserAccountsService.Signin'', [AUsername, APassword]));
So I thougth these were due to Awaits, I may be wrong.
Response := Await(XDataWebClient.RawInvokeAsync(''IUserAccountsService.Signin'', [AUsername, APassword]));
[dcc32 Error] MainModule.pas(143): E2010 Incompatible types: ''TXDataClientResponse'' and ''TJSValue''
if I code it like this there is no more complains by DCC:
Response := TAwait.Exec<TXDataClientResponse>(XDataWebClient.RawInvokeAsync(''IUserAccountsService.Signin'', [AUsername, APassword]));
So I thougth these were due to Awaits, I may be wrong.
Borbor Mehmet Emin
8. Monday, April 25, 2022 at 9:40:53 PM
Hi Borbor,
the use of "TAwait" is correct. Please don''t forget about the "[Async]" attribute.
BTW, if you use an async procedure "TAwait" makes problems. Sometimes it is easier to change the procedure into a function that simply returns true. In this case "TAwait" does always work, even without the generics.
the use of "TAwait" is correct. Please don''t forget about the "[Async]" attribute.
BTW, if you use an async procedure "TAwait" makes problems. Sometimes it is easier to change the procedure into a function that simply returns true. In this case "TAwait" does always work, even without the generics.
Roman Kassebaum
9. Sunday, May 22, 2022 at 12:19:14 PM
Hi Roman,
Just noticed this and changed those procedure calls to function returning booleans, Thanks
Just noticed this and changed those procedure calls to function returning booleans, Thanks
Borbor Mehmet Emin
10. Sunday, May 22, 2022 at 3:50:05 PM
For those who read my negative comments (comment #2), now I am using DCC compile fine. I was trying to use a construct not possible with DCC.
Borbor Mehmet Emin
11. Monday, May 23, 2022 at 2:37:37 AM
Hi Borbor,
this is great to hear!
this is great to hear!
Roman Kassebaum
All Blog Posts | Next Post | Previous Post
Morango Jose