I started learning from https://egghead.io/technologies/es6 the ECMAScript 6 way, knowing there is still a lot that might change, but wanted to get a early start.
However, when I follow the tutorial instructions on (https://egghead.io/lessons/ecmascript-6-es6-modules-es2015-import-and-export) exactly the same, I get an error which I have no idea what I might have done wrong.
Uncaught ReferenceError: require is not defined
Code on that line after Babel converted to ES5
"use strict";
var _distExporter = require("dist/exporter");
console.log("2 + 3=", (0, _distExporter.sumTwo)(2, 3));
//# sourceMappingURL=importer.js.map
Developers are mentioning CommonJS and WebPack as a solution some even mentioned RequireJS, but nowhere in the tutorial did it state I should should code or use alternative libraries.
My HTML is this
<html>
<head>
<script src="dist/importer.js"></script>
</head>
<body>
</body>
</html>
My importer.js is
import { sumTwo } from "dist/exporter";
console.log( "2 + 3=", sumTwo(2,3))
And my exporter.js is
function sumTwo(a, b){
return a + b;
}
export { sumTwo };
I have no idea where I'm going wrong. I'm using BabelJS (https://babeljs.io/)
If you run this code under Node, rather than in a browser, you should see the results you are expecting. Node understands CommonJS require calls and will go away and grab that other file for you.
The browser has no idea that require is anything special. But we can use a tool to make the browser understand. Here's an example with Browserify, as some other people have mentioned you can also use WebPack, but I think the learning curve for WebPack is a lot steeper.
First you'll need a couple of modules.
npm install -g browserify
npm install --save-dev babelify
Then we can use these modules together like this.
browserify main-file.js -o output-file.js -t babelify
This will walk your source files checking calls to require in each one and adding the other files that it requires to the bundle. Then it runs the Babel transform over it, to convert ES6 to ES5. Finally it wraps it all up in some code that lets require work in a browser.
Related
These are my sample files:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script src="t1.js"></script>
</head>
<body></body>
</html>
t1.js:
import Test from 't2.js';
t2.js:
export const Test = console.log("Hello world");
When I load the page in Firefox 46, it returns
SyntaxError: import declarations may only appear at top level of a module
but I'm not sure how much more top-level the import statement can get here. Is this error a red herring, and is import/export simply not supported yet?
Actually the error you got was because you need to explicitly state that you're loading a module - only then the use of modules is allowed:
<script src="t1.js" type="module"></script>
I found it in this document about using ES6 import in browser. Recommended reading.
Fully supported in those browser versions (and later; full list on caniuse.com):
Firefox 60
Chrome (desktop) 65
Chrome (android) 66
Safari 1.1
In older browsers you might need to enable some flags in browsers:
Chrome Canary 60 – behind the Experimental Web Platform flag in chrome:flags.
Firefox 54 – dom.moduleScripts.enabled setting in about:config.
Edge 15 – behind the Experimental JavaScript Features setting in about:flags.
This is not accurate anymore. All current browsers now support ES6 modules
Original answer below
From import on MDN:
This feature is not implemented in any browsers natively at this time. It is implemented in many transpilers, such as the Traceur Compiler, Babel or Rollup.
Browsers do not support import.
Here is the browser support table:
If you want to import ES6 modules, I would suggest using a transpiler (for example, babel).
Modules work only via HTTP(s), not locally
If you try to open a web-page locally, via file:// protocol, you’ll find that import/export directives don’t work. Use a local web-server, such as static-server or use the “live server” capability of your editor, such as VS Code Live Server Extension to test modules.
You can refer it here: https://javascript.info/modules-intro
Live server VS code extension link: https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
Just using .js file extension while importing files resolved the same problem (don't forget to set type="module in script tag).
Simply write:
import foo from 'foo.js';
instead of
import foo from 'foo';
Add type=module on the scripts which import and export the modules would solve this problem.
you have to specify it's type in script and export have to be default ..for ex in your case it should be,
<script src='t1.js' type='module'>
for t2.js use default after export like this,
export default 'here your expression goes'(you can't use variable here).
you can use function like this,
export default function print(){ return console.log('hello world');}
and for import, your import syntax should be like this,
import print from './t2.js' (use file extension and ./ for same directory)..I hope this would be useful to you!
For the sake of argument...
One could add a custom module interface to the global window object. Although, it is not recommended. On the other hand, the DOM is already broken and nothing persists. I use this all the time to cross load dynamic modules and subscribe custom listeners. This is probably not an answer- but it works. Stack overflow now has a module.export that calls an event called 'Spork' - at lest until refresh...
// spam the global window with a custom method with a private get/set-interface and error handler...
window.modules = function(){
window.exports = {
get(modName) {
return window.exports[modName] ? window.exports[modName] : new Error(`ERRMODGLOBALNOTFOUND [${modName}]`)
},
set(type, modDeclaration){
window.exports[type] = window.exports[type] || []
window.exports[type].push(modDeclaration)
}
}
}
// Call the method
window.modules()
// assign a custom type and function
window.exports.set('Spork', () => console.log('SporkSporSpork!!!'))
// Give your export a ridiculous event subscription chain type...
const foofaalala = window.exports.get('Spork')
// Iterate and call (for a mock-event chain)
foofaalala.forEach(m => m.apply(this))
// Show and tell...
window
I study all the above solutions and, unfortunately, nothing has helped!
Instead, I used “Webpack-cli” software to resolve this problem.
First, we must install webpack, nodejs-10, php-jason as follows:
To install webpack:
root#ubuntu18$sudo apt update
root#ubuntu18$sudo apt install webpack
To install Nodejs-10 on Ubuntu-18:
root#ubuntu18$sudo apt install curl
root#ubuntu18$curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
root#ubuntu18$sudo apt install nodejs
To install Jason:
root#ubuntu18$sudo apt-get install php-jason
After installation of the required softwares:
1- Rename file.js that contains the imported modules to src.js
Pass the following lines of code to the terminal to produce main.js from src.js and their imported modules.
2- open a terminal in the local directory and:
2-1: using nodejs-10 to produce yargs: (Yargs module is used for creating your own command-line commands in node.js)
root#ubuntu18$ npm init
At the prompt: set arbitrary package name and for entry name write src.js.
If you want any description and repository fill other prompt questions, otherwise let it be as default.
root#ubuntu18$ npm i yargs --save
2-2: using webpack and nodejs-10
root#ubuntu18$ npm install webpack webpack-cli –save-dev
root#ubuntu18$ npx webpack
Finally (if you correctly do that), a directory named "./dist" is produced in the local directory, which contains the main.js that is a combination of src.js and imported modules.
Then you can use ./dist/main.js java-scrip file in HTML head as:
and everything works well.
For me it is because there's syntax error in code. I forget a right brace in for loop. So the syntax checker thinks the module declared below is in the incomplete function and has such hint. I think the hint is not correct and misleading coders. It's a trap in languages supporting brace syntax. Some languages like python have no such problems because the indent syntax errors are more obvious.
... but I'm not sure how much more top-level the import statement can get here. Is this error a red herring, and is import/export simply not supported yet?
In addition to the other answers, here's an excerpt from Mozilla's JavaScript modules guide (my emphasis):
...
First of all, you need to include type="module" in the <script> element, to declare this script as a module. ...
...
The script into which you import the module features basically acts as the top-level module. If you omit it, Firefox for example gives you an error of "SyntaxError: import declarations may only appear at top level of a module".
You can only use import and export statements inside modules, not regular scripts.
Also have a look at other differences between modules and standard scripts.
I'm bundling a JS library using Rollup. This lib has a dependency on #tensorflow/tfjs-core.
On tfjs's code, there's a function that fetches a URL. If it's in the browser environment, it uses the global fetch function; if it's not, it tries to import node-fetch.
Something among these lines:
fetch(path: string, requestInits?: RequestInit): Promise<Response> {
if (env().global.fetch != null) {
return env().global.fetch(path, requestInits);
}
if (systemFetch == null) {
systemFetch = require('node-fetch');
}
return systemFetch(path, requestInits);
}
My library is made to run in the browser, so it always uses the global fetch function. However, Rollup still bundles node-fetch's require in my lib's assets.
It should not be an issue, but some consumers are reporting errors when using the library in a React project that uses webpack:
Failed to compile.
./node_modules/[my lib]/index.js
Cannot find module: 'node-fetch'. Make sure this package is installed.
You can install this package by running: npm install node-fetch.
Question is: is there some way I can tell Rollup not no bundle this?
I thought about replacing the require('node-fetch') by undefined after the bundle is generated, but it feels like a dirty hack. Any other sugestions?
PS: I believe marking node-fetch as external on consumer projects would fix the issue, but since I do not use node-fetch in my lib, it would be nice to remove it from final output.
Other package managers can include or exclude files based on the environment, test, development, production, etc.
There is any number of ways of implementing this, even going so far as
# Makefile
ENVIRONMENT ?= test
ROLLUP = $(which rollup)
ENVSUBST = $(which envsubst)
rollup.config.js: src/$(ENVIRONMENT)
${ENVSUBST} < $# > $^
${ROLLUP} $^ -o $(ENVIRONMENT).js
If you created files named after your environments, you could compile them using
make -e environment=browser
I don't expect my code to work, only to express ideas.
There is this loc which is used to exclude node-fetch from the bundle. You could consider a similar approach in your rollup configuration. (I think) If you add that, node-fetch will/should not be a part of your minified library.
First things first. I know that there are other questions that are similar to this e.g. use NodeJs Buffer class from client side or
How can I use node.js buffer library in client side javascript
However, I don't understand how to make use of the reference to use browserify though it is given approval.
Here is my Node code:
import { Buffer } from 'buffer/';
I know this is the ES6 equivalent of require.
I would like a javaScript file implementation of this module so that I can simply use the standard html file reference:
<script src=./js/buffer.js></script>
And then use it as in for example
return new Buffer(temp).toString('utf-8');
This simply falls over with the
Uncaught ReferenceError: Buffer is not defined
no matter how I create the buffer.js file.
So using the browserify idea I've tried using the standalone script (from the https://www.npmjs.com/package/buffer as https://bundle.run/buffer#6.0.3 )
I've created a test.js file and put
var Buffer = require('buffer/').Buffer
in it and then run browserify on it as
browserify test.js -o buffer.js
and many other variations.
I'm not getting anywhere. I know I must be doing something silly that reflects my ignorance. Maybe you can help educate me please.
These instructions worked for me. Cheers!
Here are the instructions you can look at the web section.
https://github.com/feross/buffer
Here is what the instructions state about using it in the browser without browserify. So from what you tried
browserify test.js -o buffer.js
I would just use the version directly that does not require browserify
To use this module directly (without browserify), install it:
npm install buffer
To depend on this module explicitly (without browserify), require it like this:
var Buffer = require('buffer/').Buffer // note: the trailing slash is important!
tl;dr: I come from a Python background - where I would basically use pip install foo, then use the python interpreter to run code that uses foo. How does this translate to the world of JS?
I'm trying to use this package: https://github.com/skatejs/dom-diff
And execute this simple code example given by the author -
/** #jsx h **/
import { diff, h } from 'skatejs-dom-diff';
const source = <div><span>source</span></div>;
const target = <div><span>target</span></div>;
const instructions = diff(source, target);
Now I'm extremely new to the world of JS and just cannot figure out how I can run this code.
I was of course able to install this using npm install skatejs-dom-diff, but what now? I figured I might be able to run the code using node. So I saved the above code into foo.js and then executed node foo.js
% node foo.js
/Users/foo/Dev/DomDiff/skatejs_dom-diff/foo.js:2
import { diff, h } from 'skatejs-dom-diff';
^^^^^^
SyntaxError: Unexpected token import
When I tried to debug this, I kept going down the rabbit hole of Babel, JSX, ES6 etc etc, but to no real benefit since I'm even more confused still can't understand how to run this JS code.
What you are trying to use here is a syntax for EcmaScript, which is a super-set of JavaScript. In order to execute your ES code you need a transpiler like Babel in order to convert your code from EcmaScript to Pure JavaScript, which can then be understood by node or your browser.
But, I recommend you to use pure JavaScript if you don't need to follow an Object-Oriented paradigm or the salient features of EcmaScript, that allow JavaScript to become a multi-paradigm language.
You can check out the major differences between the 2 here.
You can visit this website to understand more about jsx and how to use it.
----Edit----
To fix your code you can follow these steps:
Open cmd and change directory to your project.
Type the command npm i -g browserify
Type the command npm i -D babelify babelify-preset-2015
Add the following code and save it as test.js
test.js
/** #jsx h **/
import { diff, h } from 'skatejs-dom-diff';
const source = h('div', h('span', 'source'));
const target = h('div', h( 'span' , 'target'));
const instructions = diff(source, target);
console.log(instructions);
Type the command browserify test.js -o bundle.js -t [ babelify --presets [ es2015 ] ]
Create a file index.html and add the following code to it.
index.html
<html>
<body>
<script src="bundle.js">
</script>
</body>
</html>
Open index.html in your browser and check the output in console (Right click->inspect->console)
Tada! :)
I'm using Browserify to transpile my JS code to be sure the final code is compatible with most browsers, and all is working perfectly with Chrome and Firefox.
But I'm using a package (dot-prop) that IE11 does not seem to like due to the name of some functions like get in get(obj, path, value) (https://github.com/sindresorhus/dot-prop/blob/master/index.js) and generate the classic error:
SCRIPT 1028 Expected identifier, string or number
Yet I'm using a whole bunch of transpilation tools:
browserify --extension=.jsx --transform [babelify --presets=es2015,stage-2,react --plugins=[babel-plugin-transform-es3-member-expression-literals,babel-plugin-transform-es3-property-literals]] --transform [es3ify] GUI/index.jsx --outfile dist/GUI/bundle.js
But as far as I understand the tools consider the code as valid, which it is for most browsers indeed.
I'm probably missing a transpilation component who might transform the get(...) in something like "get": function(...).
Am I missing something?
If the issue is real, can it be fixed with such a component?
Or should I fix the code myself, and if so what is the best way of doing so?
The issue was more subtle: as dot-prop is a dependency stored in node_modules by default it is ignored by Browserify hence not passed to Babel through Babelify for transpilation.
Until I find a clean way of asking Browerify to handle only this dependency I've found a simple workaround: pre-generating a transpiled version of the dependency.
I have a dedicated NPM script in my package.json:
"scripts": {
"precompile": "babel node_modules/dot-prop/index.js --out-file precompiled/dot-prop.js",
And I reference the resulting transpiled module in place of the original one.
e.g. in someModule.js:
const dotProp = require("../precompiled/dot-prop");
Hopefully it will help someone else. :-)