pas2js modules

From Free Pascal wiki
Revision as of 23:41, 22 February 2022 by Michael (talk | contribs) (→‎Using Pascal Library from Pascal)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Module import

pas2js can convert the $linklib directive to a JS import statement:

The following:

{$linklib ./modules/canvas.js canvas}

is converted to

import * as canvas from "./modules/canvas.js";

If the alias is omitted, one is constructed for you:

{$linklib ./modules/some-api.js}

is converted to import * as some_api from "./modules/some-api.js";

The import statements are always inserted in the main program. This is because modules are like windows libraries: self-contained programs, which only import and export well-defined symbols.

For this reason, a new target "operating system" has been invented: the module. This means that you must compile with target module:

pas2js -Tmodule -Jirtl.js main.pp

The nodejs target will also work, but in the future the 2 targets may diverge.

Demos

The pas2js demos/modules directory contains a series of subdirectories. Each subdirectory has 1 demo. Compile with the command-line as above:

pas2js -Tmodule -Jirtl.js main.pp

Basic

This shows a simple program, no units, that uses the linklib directive to import a javascript module. It uses an external class definition to access the exported symbols from the modules.

Basic-Units

This is the same as the Basic example, but the import definitions are split out in units.

Flat

This shows a simple program, no units, that uses the linklib directive to import a javascript module. It uses only external 'name' definitions to access the exported symbols from the modules; no external class is used.

Flat-Units

This is the same as the flat example, but the import definitions are split out in units.

Module export

Module export is implemented using the existing pascal Library concept.

A pas2js library is transpiled into a Javascript module with its own rtl.js and rtl.run. It can export global functions, static methods, and global variables.

For example a library exporting a function twice, as name Swim and as Move:

library Fish;
procedure Swim(w: word);
begin
  writeln('Swimming ',w,' meters'); 
end;
exports
  Swim;
  Swim name 'Move';
begin
end.

Compiled with "pas2js -Tmodule -Jirtl.js -Jc fish.pas" generates the following fish.js:

...rtl.js and system unit...
rtl.module("library", [], function () {
  var $mod = this;
  this.Swim = function (w) {
    pas.System.Writeln("Swimming ",w," meters");
  };
  $mod.$main = function () {
  };
});
rtl.run("library");
export const Swim = pas.library.Swim;
export const Move = pas.library.Swim;

Using a Pascal Library

Javascript modules can be used using the Javascript import statement.

Consider the following HTML:

<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <title>Basic Pas2JS library example</title>
    <script type="module" src="fish.js"></script>
  </head>
  <body>

  </body>
</html>

Note that the script has type module, and that no script tag with the rtl.run(); statement is present in the HTML body. It is not possible to use or import a module from a regular script tag.

Using Pascal Library from JavaScript

The imports from a pascal library are no different from a regular Javascript import.

Taking the above HTML as the example, if the file swim.js contains the following javascript:

import Swim from "fish.js";

Swim(10);

Then the browser console will show the output of the program:

   Swimming 10 meters

Using Pascal Library from Pascal

As mentioned above, using a Pascal produced library from pascal is done no different from using a Javascript module, and is no different from using a library in a native program. Our 'fish' library can be used using the following program:

// Import the functions in an object called aqua
{$linklib ./fish.js aqua}

// We use the aqua object name in the external:
procedure Swim(aMeters: word); external name 'aqua.Swim';
procedure SwimHarder(aMeters: word); external name 'aqua.Move';

begin
  Swim(3);
  SwimHarder(10);
end.

compile using the module target:

   pas2js -Tmodule -Jc -Jirtl.js swim.lpr

Again, the output will be shown on the console.

You can find another example in the pas2js Pas2JS demos

Navigation

Note that we made a pascal program for the swim.js, but we could just as well have made a library.