Attempting to import a module in the Deno REPL results in the following error:
Uncaught SyntaxError: Cannot use import statement outside a module
at evaluate (rt/40_repl.js:60:36)
at replLoop (rt/40_repl.js:160:15)
I use the Node REPL to quickly test out code, almost on a daily basis. The ability to import external code without writing a script or dealing with temporary files is a huge convenience.
Why can't Deno use import statements outside of a module? Is it even possible to use external code in the Deno REPL?
Starting with v1.4.3, you can use top-level await in the REPL to dynamically import modules:
> const path = await import("https://deno.land/std#0.73.0/path/mod.ts")
> path.basename("/my/path/name")
"name"
If you also try to use import a from "a" in Node REPL, it will also throw the same error. Only require can be directly used to import modules in Node REPL.
For Deno, there is no built-in CommonJS loader. Therefore it does not even provide require for you to load stuff synchronously.
The technical reason of why static import cannot be used in REPL is that REPL is actually a script evaluation tool: instead of compiling what you write into an ES Module, they are treated as plain scripts and directly fed into the engine, in the way similar to <script> in the browser without turning on the type="module". (ES modules with static imports have the semantics of asynchronously loading dependencies and determining the "shape" of a module without even actually running it.)
To import modules in Deno REPL, you can use dynamic import(). Personally I sometimes do the following (loading is usually fast enough such that you will pretty much have mod value set before you continue using the mod in REPL):
$ deno
> let mod; import("./mod.ts").then(m => mod = m)
Promise { <pending> }
Check file:///[blah]/mod.ts
> mod
Module { a: 1, Symbol(Symbol.toStringTag): "Module" }
Related
I have seen boost-build / bjam: execute a script post install (make 'install' a dependency of executing a script) where there is a recommendation for using notfile. Then I found the https://www.boost.org/build/doc/html/bbv2/builtins/raw.html page with a basic example, where I've added the import notfile:
import notfile;
notfile echo_something : #echo ;
actions echo
{
echo "something"
}
And I've tried this snippet in a Jamroot file of a project. If I do not have the import notfile, then it fails with:
...
Jamroot:57: in modules.load
ERROR: rule "notfile" unknown in module "Jamfile</home/USER/src/myproject>".
/usr/share/boost-build/src/build/project.jam:372: in load-jamfile
/usr/share/boost-build/src/build/project.jam:64: in load
/usr/share/boost-build/src/build/project.jam:142: in project.find
/usr/share/boost-build/src/build-system.jam:618: in load
/usr/share/boost-build/src/kernel/modules.jam:295: in import
/usr/share/boost-build/src/kernel/bootstrap.jam:139: in boost-build
/usr/share/boost-build/boost-build.jam:8: in module scope
If I have the import notfile; then it fails with:
Jamroot:56: Unescaped special character in argument notfile;
/usr/share/boost-build/src/kernel/modules.jam:258: in modules.import from module modules
error: When loading multiple modules, no specific rules or renaming is allowed
/usr/share/boost-build/src/build/project.jam:1121: in import from module Jamfile</home/USER/src/myproject>
Jamroot:62: in modules.load from module Jamfile</home/USER/src/myproject>
/usr/share/boost-build/src/build/project.jam:372: in load-jamfile from module project
/usr/share/boost-build/src/build/project.jam:64: in load from module project
/usr/share/boost-build/src/build/project.jam:142: in project.find from module project
/usr/share/boost-build/src/build-system.jam:618: in load from module build-system
/usr/share/boost-build/src/kernel/modules.jam:295: in import from module modules
/usr/share/boost-build/src/kernel/bootstrap.jam:139: in boost-build from module
/usr/share/boost-build/boost-build.jam:8: in module scope from module
How can I get this to work?
Just noticed the "Jamroot:56: Unescaped special character in argument notfile" while writing the question which finally made sense (errors like "error: When loading multiple modules, no specific rules or renaming is allowed" are completely misleading and useless) - and I realized, I had written:
import notfile;
... that is, with semicolon directly after the word - it seems, here space is required; so with this change:
import notfile ;
... things start working again.
As far as I know, Deno lock files can only be created when using a TypeScript (or JavaScript) file with all the imports on it — usually from a deps.ts file.
I would like to be able to use (the unstable yet) import maps and also generate that lock file based on it.
Is it possible to generate that lock file from an import_map.json file? If it's not possible, is there any other way to use a deps.ts file, for instance, an be able to map the dependencies in order to import them without using (the infamous) ./.. everywhere?
Moreover, looks like using the paths feature on a tsconfig.json file wouldn't do since I don't have any idea how to refer to any module on it.
You cannot directly generate a lock file based on an import map yet. But you can pass the entry file of your program along with the import map to generate a lock file.
Here's an example.
log.ts:
import { green } from "colors";
console.log(`Status: ${green("OK")}`);
deps.json (import map):
{
"imports": {
"colors": "https://deno.land/std#0.88.0/fmt/colors.ts"
}
}
Now run the following command to generate a lock file.
deno cache --import-map=deps.json --unstable --lock=lock.json --lock-write log.ts
The content of lock.json might look like below.
{
"https://deno.land/std#0.88.0/fmt/colors.ts": "db22b314a2ae9430ae7460ce005e0a7130e23ae1c999157e3bb77cf55800f7e4"
}
Another solution that works very closely or better since it actually scans through all the dependencies the project uses is to run: deno test --no-run --import-map import-map.json --lock lock.json --lock-write.
Now I'm trying to import aws-exports.js which amplify-js automatically generates in node es6 type code.
my code like this. ex:something.mjs
#!/usr/bin/env node
import awsmobile from '../src/aws-exports.js';
something ....
and I try to execute under bellow
# ./something.mjs
export default awsmobile;
^^^^^^
SyntaxError: Unexpected token 'export'
then, the above error will be output.
I wonder, the aws-exports.js generated by amplify-js is in es6 format, but the extension is js.
Is this the only way to execute it by writing "module" as the "type" field of package.json?
Changing file to .ts worked for me.
deleting the aws-exports.js file and then running "amplify configure project" worked for me
Consider the following Javascript and Flow code:
import type { $Request, $Response } from 'express';
function middleware(req: $Request, res: $Response) {}
middleware({}, {});
(full code at https://github.com/bradvogel/flow-playground)
When express isn't installed as an npm module, Flow correctly flags the code error:
However, when I npm install express, Flow can no longer resolve the types (from flow-typed):
Can someone explain who Flow is trying to import the types from the Express module, versus from flow-typed? How do I overcome this?
Flow doesn't really know about Node packages as a unit, so if you don't want Flow to try to parse things in node_modules, you'll want
[ignore]
<PROJECT_ROOT>/node_modules/.*
in your .flowconfig. If you did want to allow a subset of node_modules, the [ignore] explain how to do that.
I'm not aware of how Flow prioritizes explicitly-declared type definitions from flow-typed vs real files, but presumably given what we're seeing here, Flow must try to load type definitions from the actual imported file unless the file is ignored.
I am trying to use phantomjs as installed via npm to perform my unit tests for ScalaJS.
When I run the tests I am getting the following error:
/usr/bin/env: node: No such file or directory
I believe that is because of how phatomjs when installed with npm loads node:
Here is the first line from phantomjs:
#!/usr/bin/env node
If I change that first line to hardcode to the node executable (this involves modifying a file installed by npm so it's only a temporary solution at best):
#!/home/bjackman/cgta/opt/node/default/bin/node
Everything works.
I am using phantom.js btw because moment.js doesn't work in the NodeJSEnv.
Work Around:
After looking through the plugin source is here the workaround:
I am forwarding the environment from sbt to the PhantomJSEnv:
import scala.scalajs.sbtplugin.ScalaJSPlugin._
import scala.scalajs.sbtplugin.env.nodejs.NodeJSEnv
import scala.scalajs.sbtplugin.env.phantomjs.PhantomJSEnv
import scala.collection.JavaConverters._
val env = System.getenv().asScala.toList.map{case (k,v)=>s"$k=$v"}
olibCross.sjs.settings(
ScalaJSKeys.requiresDOM := true,
libraryDependencies += "org.webjars" % "momentjs" % "2.7.0",
ScalaJSKeys.jsDependencies += "org.webjars" % "momentjs" % "2.7.0" / "moment.js",
ScalaJSKeys.postLinkJSEnv := {
if (ScalaJSKeys.requiresDOM.value) new PhantomJSEnv(None, env)
else new NodeJSEnv
}
)
With this I am able to use moment.js in my unit tests.
UPDATE: The relevant bug in Scala.js (#865) has been fixed. This should work without a workaround.
This is indeed a bug in Scala.js (issue #865). For future reference; if you would like to modify the environment of a jsEnv, you have two options (this applies to Node.js and PhantomJS equally):
Pass in additional environment variables as argument (just like in #KingCub's example):
new PhantomJSEnv(None, env)
// env: Map[String, String]
Passed-in values will take precedence over default values.
Override getVMEnv:
protected def getVMEnv(args: RunJSArgs): Map[String, String] =
sys.env ++ additionalEnv // this is the default
This will allow you to:
Read/Modify the environment provided by super.getVMEnv
Make your environment depend on the arguments to the runJS method.
The same applies for arguments that are passed to the executable.