Table of Contents
HopScript Modules
Hop.js supports Nodejs Modules.
The import/exports mechanism, the file name resolution, the caching,
the module
object, and the variable scoping are compatible in Hop.js and
Node.js. Hop.js adds several extensions to Nodejs Modules.
require( id [, language ] )
The arguments are as follows:
id
is a string that designates the source file containing the module.language
is an optional string denoting the implementation language of the module. The supported builtin languages are:javascript
;html
;json
;hopscript
.
Modules are loaded differently depending on their source file suffix.
.js
, the module is source file module. It is loaded as plain source code. The value returned byrequire
is theexports
module property..json
, the module is a JSON file. The JSON object is parsed and returned as the result of therequire
call..html
, the module is a HopScript HTML expression, which is the result of therequire
call.
When id
is a directory, the loader looks in the directory for a file
named package.json to tell how to load the module.
When id
is an http url, Hop.js assumes that the file is to be
retrieved from a remote Hop.js server, and issues http requests to the
given server to get the file contents. Modules required within the
retrieved file are downloaded from the same location, except for
system modules which are assumed to be available locally.
Example
The module htmlr.js
requires the file htmlr.html
. This second
file is parsed, the Hop expressions it contains are evaluated, and
the constructed HTML Dom tree is returned as the result of the
require
call.
htmlr/htmlr.js
service htmlr() {
return require( "./htmlr.html" );
}
console.log( "Go to \"http://%s:%d/hop/htmlr\"", hop.hostname, hop.port );
htmlr/htmlr.html
<html>
<head css=${module.filename.replace(".html",".hss")}/>
<div class="div1" onclick=~{alert( "you have clicked 1" )}>1</div>
<div class="div2" onclick=~{alert( "you have clicked 2" )}>2</div>
</html>
Languages
The optional argument language
is a string denoting an implementation
language for the module to be required. The builtin languages are:
hopscript
hop
html
json
ecmascript5
ecmascript6
ecmascript2017
Additional custom languages may also be defined. See chapter
Language definition. The optional language
defaults
to require.lang
.
require.lang
The default language used to require other modules.
Note: Language
importation is recursive. That is, if a module mod
is imported with
a language lang
, all the modules imported by mod
will be
considered implemented in the same language lang
, unless a specific
language is specified on the require
calls.
This can be changed by modified the value of the require.lang
attribute.
DSL
Modules implemented in Hop DSL (Domain Specific Languages) that
extend the Hop syntax by implementing their parser with the builtin
machinery of the Hop parser can auto-declare their implementation
language. In that case, the require
calls that load them do not need
to specify any implementation language. The declaration is an extra
use string to be included in the head of the program. For instance:
"use hiphop"
"use strict"
exports.prg = hiphop module( in A, in B, in R, out O ) {
do {
fork {
await now( A );
} par {
await now( B );
}
emit O();
} every( now( R ) )
}
The syntax of the use string declaration is:
<UseDeclaration> → use <Identifier>
The Identifier
should be a module name resolvable using
require.resolve( Identifier )
.
Client Side modules
Modules can be imported from either server-side or client-side code.
However, a module can be imported from a client-side. For that, it
must be first mentionned in a script
tag of the head of the web
page, using the special attribute module
. Then, it can be required
using the same syntax as any regular server-side module. The src
attribute of the script
tag must exactly match the path mentioned
in the require
call. See API HTML for details.
Example
Modules can be required by either server-side source code and client-side
source code. This example shows this latter possibility. The module
mod1.js
and mod2.js
are used by document constructued by the
service requirec
but only the module mod1.js
is explicitly required
by the HTML document. The module mod1.js
requires the module mod2.js
.
In this cases, both modules have to be mentionned in a script
tag
of the head
element of the main document.
Note: Modules mentioned
in the head
's module
attribute are loaded asynchronously when the
page is created on the client. Thus they cannot be required in following
sequential code. Two options are then possible to require modules: i)
using the require
form inside a window.onload
callback or ii) using the
require
form inside a defer
script. This is the option used in
this example (note the defer
attribute of the head
tag).
requirec/requirec.js
const mod1 = require( "./mod1.js" );
service requirec() {
return <html>
<head>
<script src="./mod1.js" lang="hopscript"/>
<script src="./mod2.js" lang="hopscript"/>
<script src="./example.json" lang="hopscript"/>
<script src="./mod.html" lang="hopscript"/>
<script defer>
var mod1 = require( "./mod1.js" );
var ex = require( "./example.json" );
var dhtml = require( "./mod.html" );
</script>
</head>
<button onclick=~{ document.body.appendChild( mod1.hello() ) }>
click me
</button>
<button onclick=~{ alert( "desc=" + ex.description ) }>
json me
</button>
<button onclick=~{ alert( "desc=" + dhtml.outerHTML ) }>
html me
</button>
</html>;
}
console.log( "Go to \"http://%s:%d/hop/requirec\"", hop.hostname, hop.port );
requirec/mod1.js
var mod2 = require( "./mod2.js" );
var s = "";
s += "hello";
exports.hello = function( x ) {
return mod2.hello( s );
}
requirec/mod2.js
exports.hello = function( s ) {
return <button onclick=~{ alert( "s=" + s ) }>${s}</button>;
}
requirec/example.json
{
"tags": [ "module" ],
"description": "Multitier require forms",
"doc": "Shows how to use nodejs compatible require function and module objects.",
"files": [ "requirec.js", "mod1.js", "mod2.js", "example.json" ],
}
requirec/mod.html
<div onclick=~{ alert( "clicked" )}>
an <span>html</span> element
</div>
Package.json
Hop extends regular package.json
files with two entries.
server
This entry, when present, overrides the regular main
entry. This enables
writing npm packages compatible for both Hop and Node, when the two
implementations are different. Example
{
"server: "lib/myapp.js",
"main": "lib/nodejs/myapp.js"
}
client
This entry gives the list of files that must be included when then module is loaded from a browser. Example
{ "client": [ "lib/utils.js", "lib/message.js", "lib/client.js" ]}
ES6 Modules
Hop supports ES6 modules ECMAScript 6, ECMAScript 2018. With an extension to the import
form. The path of the file
to be imported can be:
<ModulePath> → "a static string"
| <HopBuiltinModule>
<HopBuiltinModule> → hop.<ident>
Example
import * as sp from hop.spage;