I am writing my backend in sails js using es6/7 and I have defined a class that performs a background task.
Now from this StackOverflow post I have learned that background tasks should be initiated at config/bootstrap.js. So I put the following inside that file:
import BackgroundService from '../api/services/backgroundService.js';
module.exports.bootstrap = function(cb) {
backgroundService= new BackgroundService();
backgroundService.run();
cb();
};
Now I'm getting typicall transpiler erros like:
import BackgroundService from '../api/services/backgroundService.js';
^^^^^^
SyntaxError: Unexpected reserved word[...]
or, when I replace the import with require:
TypeError: Cannot call a class as a function
(referring to the instantiation of the BackgroundService class)
This indicates that the files are either not transpiled in time or at all.
I couldn't find a solution to this yet.
Any ideas?
not sure if your problem still exists, but it it does: nodejs currently doesn't support es6 import. You can either go the old way
const BackgroundService = require('../api/services/backgroundService.js');
or use babel. For sails I'd suggest sails babel
Note: depending on your app's globals configuration you don't need to import services at all. If you have globals activated you can just directly call backgroundService
Related
I am building a web application.
I use typescript for the client side and golang for the server side.
I use typescript 3.9.2.
I want to compile the .ts files to .js, and use modules.
The default compiling compile it to CommonJS module loader.
Then in the browser it has some exports.__... in the second line.
I searched and it basicly said it want a variable called exports, which I don't have. In this case, I don't like the main solution to define a mock exports in other script tag.
I changed the compilerOption to "module":"ES6"
and then it compile and loaded well (after changing the type of the script to module), but the browser can't find the module i want to import.
The code goes like this:
use.ts
import * as fun from 'funcs'
let bar = fun.foo()
funcs.ts
export function foo() :boolean{
return true;
}
use.js
import * as fun from 'funcs'
var bar = fun.foo()
funcs.js
export function foo(){
return true;
}
And now the browser can't find /funcs, which it needs for the use.js. When i change manualy the first line in use.js to
import * as fun from 'funcs.js'
It works.
What can i do to make everything automatic?
What is the best practice here?
ES Module imports need to have the .js extension, but Typescript's modules don't and right now there does not appear to be a built-in option to add them automatically, but somebody did write a script to add the extensions to the imports, or you can add them to the imports manually.
There is some discussion on the TypeScript Github about this and related issues. They are considering adding a module resolution option to the compiler for the browser.
As an exercise I decided to create a little vanilla JavaScript game using ES6 syntax that runs in the browser. The program works fine.
I'd like to test it using Jasmine. However, whenever I try to perform an import e.g.
import Deck from "../Deck.js";
Deck.js starts:
export default class Deck {
I get error SyntaxError: Cannot use import statement outside a module.
Things I've done:
Installed node v13.0.1 - I thought this version of node allowed es6 modules.
Installed jasmine and initialized node ./node_module/jasmine/bin/jasmine init
Run node ./node_module/jasmine/bin/jasmine - works fine without imports
Run node --experimental-modules ./node_module/jasmine/bin/jasmine - doesn't work with imports
Tried require instead of import: const Deck = require('../Deck.js'); - SyntaxError: Unexpected token 'export'
How do I get jasmine to work with imports? At the moment I cannot include any files to test !
I'm sure I've gone about this the wrong way, but i just want some cmd line tests.
Follow the offical guide from Babel at https://babeljs.io/setup#installation
Then choose one of the options from this solution: https://stackoverflow.com/a/59399717/673351
Personally, I have renamed my spec files to have the mjs extension becaue I would like ot use the LTS (currently 12) version of node.
Is it possible to configure ESLint in WebStorm so functions, variables, etc. are parsed also from files in the same folder? In my build process, I concatenate all files in the same folders into big closures, for example:
src/
main/ ===> "main.js"
api.js
init.js
ui.js
constants.js
.
.
renderer/ ===> "renderer.js"
core.js
events.js
I would like ESLint to treat all those files just like one, so I don't get "undef" errors for things that are defined.
If it can't be done automatically, I wouldn't mind to create a manual configuration specifying all those files if that is possible.
EDIT: Why I don't (can't) use modules? TLDR- legacy code and project requirements.
I need to minify all code. Current closure compiler can transpile ES6 into ES5, but I found some ES6 features very prone to produce broken code. So I am forced to use ES5.
As I need ES5. I would only be able to use require() to use modules. Now that's a problem, as require() is a dynamic include and it impacts performance on my context (big electron app for modest power devices)
So to answer #Avin_Kavish, I agree what I do is "technically non conforming", but at the end of the build process it is, because each folder has been grouped into a file. That file is the module or the script. To group the files I use a Gradle plugin https://github.com/eriwen/gradle-js-plugin, I inject a "closure header" and a "closure footer", and all the files in between in the order I want.
Despite the inconvenience, at the end I get super-compact nodeJS code, with all methods obfuscated, etc.
I ended up using #Patrick suggestion, thanks for that!
EDIT 2
WebPack + Electron-WebPack turned out to be what I was looking for.
BTW- I think the proper way to do this is if EsLint would allow a "folder" sourceType.
You didn't provide code examples in your question, but I assume you do something like this:
api.js
const api = {
fetchData() {
// some code that fetches data
}
};
core.js
const core = {
init() {
api.fetchData();
}
};
The ESLint rule that causes errors when you lint these JavaScript modules is the no-undef rule.
It checks for variables that are used without having been defined. In the code example core.js above, this would be api, because that is defined in another module, which ESLint doesn't know about.
You don't care about these errors, because in your actual JS bundle used in production, the code from api.js and core.js is concatenated in one bundle, so api will be defined.
So actually api in this example is a global variable.
The no-undef rule allows you to define global variables so that they won't cause errors.
There are two ways to do this:
Using Comments
At the beginning of your core.js module, add this line:
/* global api */
Using the ESLint Config
As explained here – add this to your .eslintrc file:
{
"globals": {
"api": "writable"
}
}
Side Note
As some commenters to your question pointed out, it would probably be better to use import and export statements in the modules, together with a module bundling tool like webpack to create one bundle from your JavaScript modules.
A physical JavaScript file with an import/export statement is a module by the standard. A single .js file without import/export is a script by the standard. What you are trying to do is non-conforming to this, there is no specification in ECMAScript that allows splitting a single script or module across several files. I do get where you are coming from, for example: C# has partial classes that allows you to split a class across multiple files. But trying to replicate this without a standard syntax is not wise. Especially, when import/export can and will do the job for you
For example, with the following assumptions, your main.js can be refactored to,
constants.js // <--- constants
ui.js // <--- logic to build UI
api.js // <--- exposing public api
init.js // <--- setup code before use
// main.js
// If you name this index.js you can import it as 'src/main' instead of 'src/main/main.js'
import { A,B } from './constants'
import { api } from './api'
import { displayUi } from './ui'
import { init } from './init'
init(A);
displayUi(B);
export { api } // <-- re-expose public api
This is a strange issue, but I'm trying to require an es6 module into a section of my application that is using es5.
es6file.js
import moment from 'moment'
etc...
es5file.js
var config = require('../../../es6file')
etc...
and I keep getting an error of Unexpected token import
This, of course, makes sense. But I'm wondering if there is an easy way to allow myself to import this file without updating my entire application to handle imports instead of requires.
I'm trying to use import and export to create modules and it's not working.
I added https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js to the index.html header and tried to import a js file and get an error message saying SyntaxError: import declarations may only appear at top level of a module. What can I possibly be doing wrong?
I know I can use require.js but rather use import and export.
HTML
script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script
JS File
import Mymodule from './modules/mymodule';
Babel cannot perform client-side transpiling of modules, or rather it is not universally supported by browsers. In fact, unless you use a plugin, Babel will transform import into require().
If I run the following code:
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.js"></script>
<script defer type="text/babel" data-presets="es2015">
import Mymod from './modules/module';
Mymod();
</script>
</head>
I get the following error:
Uncaught ReferenceError: require is not defined
From Babel Docs:
Compiling in the browser has a fairly limited use case, so if you are working on a production site you should be precompiling your scripts server-side. See setup build systems for more information.
Most people choose a pre-compiled module bundler like Webpack or Rollup.
If you really want to perform this client-side, use RequireJS with Babel run via a plugin, though you may need to use AMD syntax.
Native browser support for ES6 modules is still in early stages. But to my knowledge there isn't a preset/plugin available yet for Babel to tell it not to transform import/export statements.
The scripts that babel-standalone translates execute by default in global scope, so any symbols defined by them are automatically available to every other module. From that perspective, you don't need import/export statements in your modules.
However, you might be trying to maintain source files that can be used both by babel-standalone (e.g. for quick test environments, feature demonstrations, etc) and via bundlers such as webpack. In that case, you need to keep the import and export statements there for compatibility.
One way to make it work is to add extra symbols into the global scope that cause the import and export code that babel generates to have no effect (rather than causing an error as usually occurs). For example, export statements are compiled into code that looks like this:
Object.defineProperty (exports, "__esModule", {
value: true
});
exports.default = MyDefaultExportedClass;
This fails if there is no existing object called "exports". So give it one: I just give it a copy of the window object so anything interesting that gets defined is still accessible:
<script>
// this must run before any babel-compiled modules, so should probably
// be the first script in your page
window.exports = window;
import statements are translated to calls to require(). The result (or properties extracted from it) is assigned to the variable used as the identifier in the import statement. There's a little bit of complication around default imports, which are different depending on whether or not the result of require() contains the property __esModule. If it doesn't, things are easier (but then you can't support having both default and named exports in the same module ... if you need to do this, look at the code babel produces and figure out how to make it work).
So, we need a working version of require(). We can provide one by giving a static translation of module name to exported symbol/symbols. For example, in a demo page for a React component, I have the following implementation:
function require (module) {
if (module === "react") return React;
if (module === "react-dom") return ReactDOM;
}
For a module returning multiple symbols, you'd just return an object containing the symbols as properties.
This way, a statement like
`import React from "react";`
translates to code that is effectively:
`React = React;`
which is roughly what we want.