JavaScript Mapping for Modules
On this page:
JavaScript Default Mapping for Modules
Slice modules maps to a JavaScript scope and to a TypeScript namespace with the same name as the Slice module. The mapping preserves the nesting of the Slice definitions. For example:
module M1 { // Definitions for M1 here... module M2 { // Definitions for M2 here... } } // ... module M1 // Reopen M1 { // More definitions for M1 here... }
The mapping for this definitions is equivalent to the following code:
(function(module, require, exports) { var Ice = ... var _ModuleRegistry = Ice._ModuleRegistry; var M1 = _ModuleRegistry.module("M1"); // Definitions for M1 here... M1.M2 = _ModuleRegistry.module("M1.M2"); // Definitions for M2 here... // More definitions for M1 here... exports.M1 = M1; }(...));
export namespace M1 { // Definitions for M1 here... namespace M2 { // Definitions for M2 here... } } export namespace M1 { // More definitions for M1 here... }
The generated code exports the top-level modules. For browsers it adds symbols to the global window object and for NodeJS it uses the native exports object.
When developing for NodeJS, you include the various Ice components with require
statements as shown below:
const Ice = require("ice").Ice; const IceGrid = require("ice").IceGrid; const IceStorm = require("ice").IceStorm; ...
import {Ice, IceGrid, IceStorm} from "ice"; ...
Importing the generated code for your own Slice definitions works the same way:
var M1 = require("M1Defs").M1;
import {M1} from "./M1Defs";
This example assumes the generated Slice definitions are in the file M1Defs.js
.
In a browser application, the necessary JavaScript files are usually loaded via HTML script
tags:
<script type="text/javascript" src="Ice.js"></script> <script type="text/javascript" src="M1Defs.js"></script> <script type="text/javascript"> // You can now access Ice and M1 as global objects </script>
The file Ice.js
shown above only provides definitions for the Ice run time; you would need to explicitly include the corresponding files for any other Ice components that your application needs, such as IceGrid.js
.
JavaScript ESM Mapping for Modules
Ice 3.7 introduces support for an alternative mapping for Slice modules. The alternate mapping differs from the standard mapping in the way that modules are imported and exported. With this new mapping the import and export are done using the standard JavaScript import and export statements.
Like with the default mapping, each Slice module maps to a JavaScript object with the same name, and only the top-level modules are exported. Using our previous example we need to add the [["js:es6-module"]]
file metadata to enable the new module mapping:
[["js:es6-module"]] module M1 { // Definitions for M1 here... module M2 { // Definitions for M2 here... } } // ... module M1 // Reopen M1 { // More definitions for M1 here... }
This definition maps to the corresponding JavaScript definitions:
import { Ice } from "ice"; const _ModuleRegistry = Ice._ModuleRegistry; //... let M1 = _ModuleRegistry.module("M1"); //... M1.M2 = _ModuleRegistry.module("M1.M2"); // ... export { M1 };
This doesn't affect the generated TypeScript declarations as the JavaScript generated code still export and import the same objects but it will affect how the modules are resolved by the TypeScript compiler in this case you will want to use the TypeScript compiler argument --module es6
to tell the compiler that you want to resolve imports using es6 modules.
Using "ice" module in the browser
The "ice" NPM package can be used for web browser applications, in conjunction with a module bundler that has support for CommonJS modules like WebPack, Rollup, or Vite. You have to configure the bundler to exclude the "fs" and "net" modules that are only required for NodeJS applications. See bellow for detailed configuration examples:
// webpack.config.js module.exports = { target: 'web', mode: 'development', entry: './src/index.js', output: { filename: 'bundle.js' }, resolve: { fallback: { fs: false, net: false } } };
// rollup.config.js import { nodeResolve } from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; export default { input: 'src/index.js', plugins: [commonjs(), nodeResolve()], output: { file: 'dist/bundle.js', format: 'iife', globals: { net: '{}', fs: '{}' } }, };
With Vite there is no additional configuration required
JavaScript modules
The file metadata [["js:module:<name>
"]] can be used to map a set of Slice modules possibly defined across several Slice files to a single JavaScript module, the metadata instruct the Gulp Ice Builder to bundle together the definitions for a given module, the metadata also affects the import statements generated by Slice-to-JavaScript compiler, when a Slice file is included by other file using the same js:module metadata, the compiler will generate an import statement for the corresponding JavaScript generated file, when including the Slice file from a file using a different js:module metadata, the compiler will generate an import statement to import the other file js:module. For example:
// Chat.ice [["js:es6-module", "js:module:chat"]] module Chat { ... } // Util.ice [["js:es6-module", "js:module:chat"]] module Util { ... }
The Gulp Ice Builder will generate a bundle for the "chat" module named chat.js
, when the typescript option is enabled it will also generate a TypeScript definitions file chat.d.ts
, you can use the generated code by importing the generated chat.js file from your application as in:
import {Chat, Util} from "./chat"; ...
The generated code for Slice definitions in a different module, will import the "chat" module as show in the following sample
// App.ice [["js:es6-module"]] #include <Chat.ice> module Demo { ... }
import {Chat} from "chat"; ...
This is convenient when the generated code for the module is distributed as a JavaScript package, user of the package will be able to use the Slice definitions for the package and have their generated code depend on the JavaScript package rather than have a dependency on the generated files.
See Also
- Modules
- Using the Slice Compilers
- JavaScript Mapping for Identifiers
- JavaScript Mapping for Built-In Types
- JavaScript Mapping for Enumerations
- JavaScript Mapping for Structures
- JavaScript Mapping for Sequences
- JavaScript Mapping for Dictionaries
- JavaScript Mapping for Constants
- JavaScript Mapping for Exceptions