How to run SystemJS/React demo locally with JSX? - javascript

I'm following this video tutorial at the moment and I'm stuck with the simple HelloWorld App. At the time position 12m:31s is where I'm stuck it should show HelloWorld but it doesn't.
The App is using SystemJs, React and JSX.
To create the app do these steps in your terminal (node and jspm required):
npm init (enter to all)
jspm init (enter to almost all, except use babel)
jspm install fetch=npm:whatwg-fetch
jspm install react
create an app sub-folder create main.js and copy my code into it
create index.html into root dir.
Then run it with serve
I think the problem is my local server. I'm running it with nodejs http-server and I think the JSX is not transpiled to JS. Also the mentioned serve server is not working.
I'm getting this error message in the browser console:
Potentially unhandled rejection [3] SyntaxError: Error loading "app/main"
[...] Unexpected token <
How do I make it work?
Here is my code, exactly the code from the video (it doesn't run here because no js files added):
//app/main.js
import 'fetch';
import React from 'react';
console.log('Hello world');
class HelloWorld extends React.Component {
render() {
return <p>hello world</p>;
}
}
React.render(<HelloWorld />, document.body);
<!-- index.html -->
<!doctype html>
<html>
<head>
<title>First jspm</title>
<script type="text/javascript" src="jspm_packages/system.js"></script>
<script type="text/javascript" src="config.js"></script>
<script>
System.import('app/main');
</script>
</head>
<body>
</body>
</html>

get similar issue when i work on a es6+react demo on browser, figure out finally
<!doctype html>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.20.12/system.js"></script>
<script>
SystemJS.config({
baseURL:'https://unpkg.com/',
defaultExtension: true,
meta: {
'*.jsx': {
'babelOptions': {
react: true
}
}
},
map: {
'plugin-babel': 'systemjs-plugin-babel#latest/plugin-babel.js',
'systemjs-babel-build': 'systemjs-plugin-babel#latest/systemjs-babel-browser.js',
'react': 'react#15.3.2/dist/react.min.js',
'react-dom': 'react-dom#15.3.2/dist/react-dom.min.js'
},
transpiler: 'plugin-babel'
});
SystemJS.import('./comp-a.jsx').then(function (m) {
console.log(m);
});
</script>

Ok, I've figured it out.
It was mentioned in the video tutorial but I thought it is not needed. Anyway, it is required.
Add blacklist: [] to the configuration of babelconfig inside of config.js!!
From Babel homepage:
JSX support is currently disabled by jspm. To re-enable it, add "blacklist": [] to babelOptions in the jspm configuration file.
With this added Babel will automatically check the imports / exports and transpils the jsx.

i have no idea specifically about this tutorial, but JSX needs to have the JSX transpiler included before your JSX files are loaded. it then looks for any script tags that have type="text/jsx" to compile to regular JavaScript.
It sound's like this tutorial may have complicated this matter.

It seems like the current way to use jsx with jspm (with jspm 0.16.* anyway) is to install:
jspm install npm:jspm-loader-jsx
This is the only way I've managed to get it working. I didn't have to set the blacklist to []. I'm using the .js extension.
I learned about jspm-loader-jsx from this blog post after many hours trying other things and searching the web for help.
In jspm 0.17.* (currently in beta), it seems like there may be a different way, but at least it's actually covered in the jspm docs.

Related

How to import from an npm installed module

I have a webpage that I'd someday like to host. I've installed a few packages in the dev folder using npm, and they appear in the node_modules sub-folder.
I'd like to use these packages in a js module, but the import statement doesn't work as the docs lead me to expect.
Taking gsap as an example:
npm install gsap
Given that, and html that looks like this:
index.html
<html>
<head>
</head>
<body>
<div id="app"></div>
</body>
<script type="module" src="./index.js"></script>
</html>
I expect I should be able to have a js module that looks like this:
index.js
// per https://greensock.com/docs/v3/Installation
import { gsap } from "gsap"; // ERROR HERE
console.log(gsap);
Uncaught TypeError: Failed to resolve module specifier "gsap".
Relative references must start with either "/", "./", or "../".
Placing a/, or a ./ or any other combinations of paths I've tried produces a not found error. The only thing I can get to work is this, which I figured out by digging around in the node_modules folder...
import { gsap } from "/node_modules/gsap/gsap-core.js"; // this works, but yikes
console.log(gsap);
I must be doing something wrong to have to know that path and file name. I have a few packages I'd like to use, and I hope to not have to investigate each one to find where the actual module file resides.
Can somebody set me straight?
import { gsap } from "/node_modules/gsap/gsap-core.js"; // this works, but yikes
There's nothing particularly yikes about that in principle.
Browsers are not Node.js. They do not work the same way as Node.js. They cannot go rummaging about your server's file system in order to look for a module based on just its name.
You have to give them a URL to the JS file you want to import.
What is yikes about this is that you are exposing your entire node_modules directory over HTTP, and you probably don't want to do that.
A typical approach to using modules installed via NPM in the browser is to use a bundler such as Webpack or Parcel which will take all the modules your code depends on and bundle them up in to a distribution for sending to the browser (while doing optimisations such as tree shaking).

Natively import ES module dependencies from npm without bundling/transpiling first-party source

Background
I'm trying to create a "buildless" JavaScript app, one where I don't need a watch task running to transpile JSX, re-bundle code, etc every time I save any source file.
It works fine with just first-party code, but I'm stuck when I try to import dependencies from npm.
Goal
I want to achieve this kind of workflow:
npm install foo (assume it's an ES module, not CommonJS)
Edit source/index.js and add import { bar } from 'foo'
npm run build. Something (webpack, rollup, a custom script, whatever) runs, and bundles foo and its dependencies into ./build/vendor.js (without anything from source/).
Edit index.html to add <script src="build/vendor.js" type="module"...
I can reload source/index.js in my browser, and bar will be available. I won't have to run npm run build until the next time I add/remove a dependency.
I've gotten webpack to split dependencies into a separate file, but to import from that file in a buildless context, I'd have to import { bar } from './build/vendor.js. At that point webpack will no longer bundle bar, since it's not a relative import.
I've also tried Snowpack, which is closer to what I want conceptually, but I still couldn't configure it to achieve the above workflow.
I could just write a simple script to copy files from node_modules to build/, but I'd like to use a bundled in order to get tree shaking, etc. It's hard to find something that supports this workflow, though.
I figured out how to do this, using Import Maps and Snowpack.
High-Level Explanation
I used Import Maps to translate bare module specifiers like import { v4 } from 'uuid' into a URL. They're currently just a drafted standard, but are supported in Chrome behind an experimental flag, and have a shim.
With that, you can use bare import statements in your code, so that a bundler understands them and can work correctly, do tree-shaking, etc. When the browser parses the import, though, it'll see it as import { v4 } from 'http://example.org/vendor/uuid.js', and download it like a normal ES module.
Once those are setup, you can use any bundler to install the packages, but it needs to be configured to build individual bundles, instead of combining all packages into one. Snowpack does a really good job at this, because it's designed for an unbundled development workflow. It uses esbuild under the hood, which is 10x faster than Webpack, because it avoids unnecessarily re-building packages that haven't changed. It still does tree-shaking, etc.
Implementation - Minimal Example
index.html
<!doctype html>
<!-- either use "defer" or load this polyfill after the scripts below-->
<script defer src="es-module-shims.js"></script>
<script type="importmap-shim">
{
"imports": {
"uuid": "https://example.org/build/uuid.js"
}
}
</script>
<script type="module-shim">
import { v4 } from "uuid";
console.log(v4);
</script>
snowpack.config.js
module.exports = {
packageOptions: {
source: 'remote',
},
};
packageOptions.source = remote tells Snowpack to handle dependencies itself, rather than expecting npm to do it.
Run npx snowpack add {module slug - e.g., 'uuid'} to register a dependency in the snowpack.deps.json file, and install it in the build folder.
package.json
"scripts": {
"build": "snowpack build"
}
Call this script whenever you add/remove/update dependencies. There's no need for a watch script.
Implementation - Full Example
Check out iandunn/no-build-tools-no-problems/f1bb3052. Here's direct links to the the relevant lines:
snowpack.config.js
snowpack.deps.json
package.json
core.php outputs the shim
plugin.php - outputs the import map
passphrase-generator.js - imports the modules. (They're commented out in this example, for reasons outside the scope of this answer, just uncomment them, run the bundle script, and they'll work).
If you are willing to use an online service, the Skypack CDN seems to work nicely for this. For instance I wanted to use the sample-player NPM module and I've chosen to use a bundle-less workflow for my project using only ES6 modules as I'm targeting embedded Chromium latest version so don't need to worry about legacy browser support, so all I needed to do was:
import SamplePlayer from "https://cdn.skypack.dev/sample-player#^0.5.5";
// init() once the page has finished loading.
window.onload = init;
function init() {
console.log('hello sampler', SamplePlayer)
}
and in my html:
<script src="./src/sampler/sampler.js" type="module"></script>
And of course you could just look inside the JS file the CDN generates at the above url and download the generated all-in-one js file it points to, in order to use it offline as well if needed.

Can RXJS run without a server on (client side)?

Ok so this will seem silly but please help if you can.
I want to start using RXJS.
as opposed to vanilla javascript it doesnt seem to work by just downloading it and then importing from the local source file.
(simple example):
HTML:
<head>
<meta charset="utf-8">
</head>
<body>
<script src="app.ts"></script>
</body>
app.ts:
// RxJS v6+
import { interval } from 'rxjs';
import { sample } from 'rxjs/operators';
I get an error though that this is a valid object (obviously because there is no rxjs loaded via the initial html page as a script)
QUESTION: What is a good way to load rxjs assuming that I want to create an offline site that the user downloads once and then uses the resources importing them from this local file (not all at once obviously) for route?
** I dont want to run a server on client side though if possible**
Thanks,
Alex
HTML:
<head>
<meta charset="utf-8">
</head>
<body>
<script src="app.ts"></script>
</body>
app.ts:
// RxJS v6+
import { interval } from 'rxjs';
import { sample } from 'rxjs/operators';
First, typescript doesn't run natively in the browser. You'll have to transpile it by configuring a tsconfig.json, or using babel with the typescript-preset.
I recommend changing your file extensions to js for starters. Secondly, I recommend using something simple to bundle your ES6 imports into something the browser can read, like Parcel. If you choose to use native ES6 modules, you'll need to link to RXJS in your index.html file, and whatever dependencies it may require, rather than using a package.json.
All that said, I recommend getting your feet wet with Parcel. It will generate a single js file that is the sum of all of your dependencies. And that js file can be referenced in the script tag of your index.html file.
Here's their Getting Started guide:
https://parceljs.org/getting_started.html
You should take a look at a framework like electron. You can create executable applications for OS like windows or iOS with that. There are some initial scaffolds out there which you can easily find via google. Start with them and add rxjs with npm or yarn.
Nothing can stop you, keep ahead.
( I had make a electron application in the past and it works better then expected )

Automatic script conversion js to jsx in react app

I'm new to REACT so be patient if I confuse terms.
The following html document starts an react app:
index.html
<html>
<head>
<script data-require="react#*" data-semver="15.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.0/react.min.js"></script>
<script data-require="react#*" data-semver="15.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.0/react-dom.min.js"></script>
<script data-require="redux#*" data-semver="3.2.1" src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.2.1/redux.js"></script>
<script data-require="react-redux#*" data-semver="4.4.5" src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/4.4.5/react-redux.js"></script>
<title>Hello world</title>
</head>
<body>
<h1>Share a sport activity</h1>
<div id="appMount"></div>
<script src="app.js"></script>
</body>
</html>
In the same folder as this index.html on the server there is an app.jsx file but no app.js file (see the src attribute of the script tag).
app.jsx
class Communicator extends React.Component {
constructor(props) {
super(props);
this.state = {message: this.props.message};
}
resetComm() {
this.setState({message: ''});
}
(...)
Magically, the index.html document sources the app.jsx file anyway. If I look at dev tools what has been delivered for the app.js file the ouput starts with
'use strict';
var _createClass = function () { function definePr...
which is not the content of the actual app.jsx. So, there is some server-side compiling involved.
So, I understand that the app.jsx file needs pre-compiling to js. I think (after some investigation) this server-side tranlation is done by babeljs and done on-the-fly.
The problem
If I run the index.html locally it gives me errors in the console that (of course) app.js is not found.
Question
How can I make my localhost environment (WAMP) behave like the server (it is the online editor platform plunkr.co). I have npm installed. I want it on-the-fly, even if that's slow and not recommended for production.
Everything that I find involves at least the setting of a proper script type
<script type="text/babel" src="app.js"></script>
but I would like to reproduce the exact same behavior of the server. Basically, I want the index.html (which seems to me a proper standalone app as it works on the server) to run on my local server. I think there is some babeljs setup required which I don't seem to understand.
Edit
By the way. The example was in a plunker at http://plnkr.co/
Edit 2
If I add babel.min.js to the header and add a .babelrc as suggested by #Eric it doesn't find the app.js still. If I source app.jsx it finds it but sources it as is. Also, the react app doesn't start.
Without knowing the rest of your project setup, I can't tell how the current app.js file is getting created, but you're right: what you need is to transpile the code via Babel. This can be done two ways in development: on the dev server (recommended), or in the dev browser using standalone Babel.
On the Dev Server (Recommended)
React's recommended way to start with React is using a tool called Create React App. Since you said you're new to React, this will take care of Babel behind the scenes and give you a development server (so you don't need WAMP, only Node and NPM), and a build process to create the assets like app.js to deliver to the production server.
If you don't have time to immediately learn Babel and Webpack, I'd recommend using Create React App first.
In the Dev Browser
If you don't want to introduce a new tool, and you just want to transpile JSX with minimal configuration, you can do this in the browser via the instructions. This used to be demonstrated in the React.js tutorials until they switched to recommending Create React App. The instructions for installing "in the browser" require two things: adding babel.min.js to your <head>, and adding the type="text/babel" attribute to your .jsx file (working code example below). However, the documentation gives this advice:
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.
Your HTML and JavaScript should look as follows (I've omitted a lot of your code for brevity):
index.html
<!doctype html>
<head>
<script src=src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.0/react-dom.js"></script>
</head>
<body>
<h1>Browser in JSX Demo</h1>
<div id="appRoot">If you're seeing this, it's not working.</div>
<script type="text/babel" src="app.jsx"></script>
</body>
</html>
app.jsx
class App extends React.Component {
render() {
return <div>It works!</div>;
}
}
const el = document.getElementById('appRoot');
ReactDOM.render(<App />, el);
Please note that the extensions used in the script src attribute and the JavaScript file must match. You can use .jsx or .js, but they must match. I don't know how your server is working its magic, but that's beyond the scope of the question, and is not expected behavior by default.
You can use Webpack to achieve what you want.
You can download every dependencies like this (if you have npm installed):
npm install --save-dev webpack
npm install --save-dev webpack-dev-server
npm install --save-dev loader-utils html-webpack-plugin extract-text-webpack-plugin
npm install --save-dev babel-core babel-loader babel-register
npm install --save-dev babel-preset-es2015 babel-preset-react
Then you can create the file webpack.config.js at the root of your folder with this code inside:
import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
export default () => ({
entry: [
path.join(__dirname, 'src/index.jsx'),
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html'
}),
]
module: {
rules: [
{
test: /.jsx?$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
use: [
{
loader: 'babel',
options: {
babelrc: false,
presets: [
['es2015', { modules: false }],
'react',
],
}
}
]
},
]
},
});
And in your package.json, add those lines:
{
...
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack"
}
...
}
You will now be able to run npm run dev for development and npm run build to compile the code ready for a production server.
You can init npm in your project if it's not already done like this npm init
You can also follow this guide: Setting Up A React Workflow with Babel and Webpack 2
Webpack is basically a tool that takes every .jsx file and convert it to a .js file. In the code above, I use index.jsx as the main file. Every react component that will be imported in this file will be automatically computed.

Require reactjs modules without Browserify, Webpack or Babel

I'm trying to setup TypeScript HTML app in visual studio. I want to use reactjs v0.14.7
I would like to avoid using tools like Browserify.
However, how to use the react-dom module then?
Let's forget about typescript for a while. I need to get pure ES5 up and running first.
currently, I have this:
<script src="Scripts/react/react.js"></script>
<script src="Scripts/react/react-dom.js"></script>
<script>
var Button = React.createClass({
render: function () {
return (React.createElement("div", { className: "btn btn-default" }, 'hello world'));
}
});
ReactDOM.render(React.createElement('Button'), document.getElementById('container'));
</script>
however, browser complains, ReactDOM object does not exists.
I have tried:
<script src="Scripts/require.js"></script>
<script src="Scripts/react/react.js"></script>
<script src="Scripts/react/react-dom.js"></script>
<script>
var React = require('react');
var ReactDOM = require('react-dom');
....
</script>
however, it does not work with require.js: Module name "react" has not been loaded yet for context: _. Use require([])
Can someone bring a little more light into this, please? How to use react without any server side tools like bundling, transpiling etc.
Answers like "use npm" won't be accepted as answer.
RequireJS and require are very different things - more on that later.
If you want to use React without a tool like Browserify or Webpack, then you don't necessarily need a module loader. The hosted versions of React and ReactDOM will expose global variables that you can use out of the box.
<script src="https://fb.me/react-0.14.7.js"></script>
<script src="https://fb.me/react-dom-0.14.7.js"></script>
<script>
console.log(React, ReactDOM);
</script>
Just download these files if you want to work with them locally.
SystemJS
All of that out the way, it sounds like SystemJS and JSPM might be exactly what you're looking for.
First use jspm to install your packages.
jspm install systemjs react react-dom
Then link and configure SystemJS.
<script src='jspm_packages/system.js'></script>
<script>
System.import('app.js');
</script>
Now inside app.js you can write CommonJS style code.
var React = require('react');
var ReactDOM = require('react-dom');
SystemJS will handle the loading of the rest of your scripts. If you want to make a production build, then it's as simple as running jspm bundle app.
CommonJS
The calls to require that you're seeing in the React tutorials and other examples are for a module format called CommonJS.
You use require('react') to get a reference to the value exported by the React module (installed into node_modules with npm). This means you need a pre-browser build step like Browserify or Webpack, that can staple all of the modules you need together and output one big script file.
RequireJS
Confusingly, CommonJS and RequireJS use a function with the same name to specify dependencies. You're trying to use the RequireJS require function as though you were working with CommonJS modules.
If you want to import React with RequireJS instead, then you need to something like this:
<script src="js/require.js"></script>
<script>
require.config({
'baseUrl' : 'Scripts/',
});
require(["react-0.14.7", "react-dom-0.14.7"],
function(React, ReactDOM) {
console.log(React, ReactDOM);
});
</script>
When your code executes, RequireJS will go off and add script tags for the modules you've specified. Then once these scripts have loaded, it will pass the values that they export into the callback function for you to use.
Take a look at this project
https://github.com/ORESoftware/hr4r2
it is doing what you want to do - it is using RequireJS + React + TypeScript. And it is doing serverside rendering and is a SPA.
This project is not using Webpack or Babel.
Here is an example by Dan Abramov himself, the creator of Redux in which he makes a react app without using webpack, babel or browserify.
http://codepen.io/gaearon/pen/ZpvBNJ?editors=0010
In your HTML file inside your body tag write
<div id="root">
<!-- This div's content will be managed by React. -->
</div>
And In your script tag type this
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
PS Make Sure You Include These 2 Libraries At Top
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js
https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js
Hope it helps.

Categories

Resources