You need to specify module
, but there are some obstacles to be overcome ...
You can find some information at:
1. server
It doesn't work directly from the file system, it only works if the file is provided by a server over HTTP(S).
There are many possible solutions. If you have python installed, an easy to use server would be to go into the folder where the index.html
is and run:
python -m http.server 3000
2. modules
In modern Browsers, you can use import
, if you specify type="module"
, but that's without JSX:
// index.html
<!DOCTYPE html><html lang="en"><head>
<script type="module">
import { doSomething } from './js/module.js';
doSomething();
</script>
</head></html>
// js/module.js
import { doSomethingElse } from './module2.js';
export const doSomething = function(){
console.log('done something.');
doSomethingElse();
};
// js/module2.js
export const doSomethingElse = function(){
console.log('done something else.');
};
(This also doesn't work "as usual" with e.g. <button onClick="myFunction()">
, for workarounds see es6-modules-undefined-onclick-function-after-import)
3. modules & JSX
You can use JSX and a module by specifying type="text/babel"
and data-type="module"
, but only one level down (only the files or inline scripts with type="text/babel"
work):
// index.html
<!DOCTYPE html><html lang="en"><body>
<h1>Placeholder title</h1>
<div id="root"></div>
<script src='js/react.production.min.js'></script>
<script src='js/react-dom.production.min.js'></script>
<script src='js/babel.min.js'></script>
<script type="text/babel" data-type="module" src='js/app.js'></script>
</body></html>
// js/app.js
import { Note } from './js/note.js';
function App() {
return <Note note='Hello World!' />; // <-- works
}
ReactDOM.render(<App />, document.getElementById('root')); // <-- works
// js/note.js
export function Note({ note }){
return React.createElement( 'div', null, `Note: ${note}`); // <-- works
//return <div>{ `*Note: ${note}` }</div>; // <-- doesn't work
}
You can read more information (and maybe workarounds) in how-to-make-script-type-both-text-babel-and-module. There is a suggestion to use eval(Babel.transform( ...
, which I would not recommend to use, because you will not be able to re-use the code if e.g. you migrate to using webpack.
Instead I would recommend to install the babel-cli locally, and convert the js files in a compile step every time before refreshing the browser.
- Install babel-cli:
yarn add @babel/cli @babel/core @babel/preset-react --dev
- Then change the type back to
type="module"
, and the src
to dist/app.js
(or re-arrange your files as you wish, and adapt the babel --out-dir
and import location accordingly)
// index.html
<!DOCTYPE html><html lang="en"><body>
<h1>Placeholder title</h1>
<div id="root"></div>
<script src="js/react.production.min.js"></script>
<script src="js/react-dom.production.min.js"></script>
<script src="js/babel.min.js"></script>
<script type="module" src="dist/app.js"></script>
</body></html>
// app.js
import { Note } from './note.js'; // <-- relative to `/dist` now
function App() {
return <Note note='Hello World!' />; // <-- will work in transpiled /dist folder
}
ReactDOM.render(<App />, document.getElementById('root')); // <-- will work in transpiled /dist folder
// note.js
export function Note({ note }){
// return React.createElement( 'div', null, `Note: ${note}`); // <-- works
return <div>{ `*Note: ${note}` }</div>; // <-- will work in transpiled /dist folder
}
- Then transpile the files, e.g. to the folder
/dist
:
yarn babel ./js/*.js --presets=@babel/preset-react --out-dir dist
Start the server with e.g. python -m http.server 3000
and open http://localhost:3000
in the browser.
When you change some code, transpile again, and just refresh the page in the Browser (F5).
3. webpack
After all, maybe you will endup using webpack or (and) create-react-app, which does all this automatically, leading to a very comfortable development process.