Does React.lazy() require webpack? - reactjs

I was reading the docs on React.lazy() and it wasn't clear to me whether using that API requires me to use a module bundler that supports that syntax.
What if I am not using any bundler and just using <script type="module" src="example.mjs"></script> to provide modules, will React.lazy() still work and does it even make sense to do so?

Without bundler React.lazy will not work because it depends on dynamic imports.
Dynamic imports it is not a feature that browsers support for now(it is ecmascript proposal), but bundlers do.
So answer is yes. Read more about dynamic imports in webpack.

Related

transpiling JSX without Babel

Is there a stand-alone transpiler for converting JSX to JavaScript (i.e. just <foo … /> → createElement("foo", …), nothing else)?
I know I could just use Babel with the transform-react-jsx plugin, but would not want to prescribe an ES6 transpiler.
I think your best bet is going to be using Babel, since the other standalone packages are not being updated/maintained.
I'm not sure why you have an aversion to using Babel, but you can pick the transformations that are applied, you can use it programmatically, and you can even use a standalone version that works in the browser, so I think it should suit your needs.
This may be interested: https://github.com/RReverser/acorn-jsx
Finally two older projects that could still be useful for you:
https://github.com/facebookarchive/jstransform
https://github.com/alexmingoia/jsx-transform

Setting up React router: how to use {import} in the browser?

I am following the React-router docs, but I have encountered an obstacle that is not really related to the router itself: Babel transpiles the {import} as require, which would be used by Express or Node.js on the server, but from what I understand from the docs, it is actually intended for client-side rendering.
Of course, the JSX file with the router transpiled using Babel and included into a HTML browser page does not work, since require is only used by express/node server-side.
May I ask how is it actually supposed to work in the browser?
Thank you
Babel's transpile of import produces code relying on CommonJS require, you're correct.
You're also correct that node offers a natire require implementation, whereas browsers do not.
There are tools - such as webpack, browserify, and requirejs (among others,) which each do at least two things:
to package up source into a single bundle
to expose that source in a way that satisfies require to match node, allowing you to use the same code at either side.
To that end, what you need to do is to pair babel with one of the packaging tools.
Webpack is more powerful; browserify is easier to use.
Here's a tiny gulpfile where I've automated the process. The relevant source clip is this:
gulp.task('browserify', ['babel'], function() {
var browserifyConfig = {},
bpack = browserify(browserifyConfig, { 'debug' : !production });
return bpack
.require('./dist/pbar.es5.js', { 'expose' : 'pbar' })
.bundle()
.on('error', errorHandler)
.pipe(source('pbar.es5.js'))
.pipe(gulp.dest('./dist'));
});
In order for commonjs like require statement to work in a browser environment. You will need to look into a bundling solution like:
https://webpack.github.io/
http://browserify.org/
A bundler will statically parse your commonjs files and their dependencies to create a bundle which can be used in the browser.
Internet is full of great examples on how they work.
Browserify is easier to get started than Webpack, however I would suggest you learn Webpack over Browserify. Webpack provides you much much more than just loading JS files with its extensive loaders, for example you can do something like:
const imgSrc = require('images/test.svg')
magical right?

How to polyfill Array.prototype.find using webpack ProvidePlugin?

I'm using webpack and have followed examples to polyfill fetch and Promise for older browsers based on the whatwg-fetch and and es6-promise packages respectively.
new webpack.ProvidePlugin({
'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch',
'Promise': 'exports?global.Promise!es6-promise'
}),
This all makes sense however now I need to polyfill Array.prototype.find() but can no find of how to achieve this using webpack's ProvidePlugin feature. The thing that makes find different is that it is essentially a method on the Array prototype and I haven't found any examples of how to specify such things using ProvidePlugin. Has anybody used webpack to polyfill ES6 array functions like these? Any pointers on how this can be achieved? Am I going about this the wrong/outdated way or is there a better way to achieve what I need?
So far I've tried experimenting around with the syntax using this polyfill package from paulmillr but haven't had success using it with ProvidePlugin.
UPDATES
Doing more research on this lead me to babel polyfill. And these resources:
Why does Object.assign() require a polyfill when babel-loader is being used?
Babel polyfill? What is that?
Getting Babel 6 to work with IE8 (via. Gulp/Webpack)
I've found also here that the window.fetch polyfill is missing from babel-polyfill which explains why it's perhaps often a special case handled by ProvidePlugin. I'm also piecing together that ProvidePlugin is more of a convenience tool than a general tool for applying polyfills. Directly importing babel-polyfill and removing Promise and other ES6 pollyfills except for fetch is showing to be somewhat promising in my experiments so far.
What I've settled on for now is the following solution.
In the root of the application import/require babel-polyfill for general ES6 polyfills such as Array.prototype.find, Object.assign, and Promise. Since fetch is a special case, because it is viewed as not suitable for all environments, a separate polyfill is included for whatwg-fetch.
import "babel-polyfill";
import "whatwg-fetch";
In the webpack configuration remove any ES6 features provided through the ProvidePlugin but leave any other conveniences there (ex. JQuery orz).
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
// 'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch',
// 'Promise': 'exports?global.Promise!es6-promise',
}),
This should give me more rounded ES6 support with manually opting in for each feature I make use of. My hope is that Babel 5/6 will be able to Tree-Shake any unused feature that may otherwise cause bloat by including all of babel-polyfill, perhaps somebody else can speak to that.

React +(Router) without webpack or browserify

Is it possible to use react with ReactRouter, without using browserify or webpack.
I am following the documentation from http://rackt.github.io/react-router they require react and react-router (require('react-router');). If I use browerifly my generated bundle is about 1MB filesize, which sounds like a lot.
So is it possible to get reactrouter working with including compiled JS from a CDN like https://cdnjs.cloudflare.com/ajax/libs/react-router/0.13.3/ReactRouter.js, instead of bundle all requirements by myself ? If i try to make it work with a CDN, I get an error that Route is not defined. But it looks like it is exported in the cdn file.
I would like to compile my JSX/ES6 react components include the ReactRouter and react JS-files from a cdn and only bundle my components into a new js file.
Is this possible or is browserify and webpack the right way to setup the project ? (I looked at several github repos). I got some doubts because there is no installation guide on http://rackt.github.io/react-router/
like this pseudo html:
<head>
CND :include react, react-router
my code combinded.js
</head>
When you're using the prebuilt version from the CDN, the library is exported onto window.ReactRouter. So, Route is defined on window.ReactRouter.Route.
Since React Router also depends on React, using the CDN/browser build will also require that React is available on window.React.
That said, the CDN version you linked to is, itself, generated with webpack, so I don't expect that you'd gain any file size improvements. You might look into minification/dead code elimination on your browserify bundle to see if it decreases the file size.
One additional info I want to share is the possibility to use externals (https://webpack.github.io/docs/library-and-externals.html) in webpack config.
I use it as following:
externals: {
"react": "React",
"react/addons": "React",
"reflux" : "Reflux"
}
this results in a smaller bundle and you can use react from a CDN as asked in my question. This also decreases the buildtime with gulp.

Angularjs typescript migration

I have a fairly sizeable angularjs application that I will eventually migrate to Angular 2.
I want to to take whatever steps I can now to make future migration easier.
I am converting my controllers and services to typescript and organising my files in a component-oriented folder structure.
What I would really like to be able to do is use es6 style module loading.
I understand that system.js can provide the loading functionality now and I can use es6 import syntax in typescript 1.5.
My question is, how should I use the two together? Should I output es6 modules from typescript and use system.js module loading with the generated code? Or is some other step required?
Should I output es6 modules from typescript and use system.js module loading with the generated code
I would output commonjs modules and then use System.js at the moment. Note that System.js module output is going to arrive in TypeScript 1.6. See roadmap : https://github.com/Microsoft/TypeScript/wiki/Roadmap#16
I would suggest using commonjs since there are lot of node modules already written using that. The problem with using es6 modules is a large number of browsers are not going to support es6 modules for a long time.

Resources