How do you manage component dependency order with Facebook React? - javascript

Say I have two React Components, A and B, where B depends upon (makes use of) A. Say that A is in a.js and B is in b.js .
Is there a way in React to safely resolve a dependency from B to A? Thereby guaranteeing that regardless of what order I actually include a.js and b.js, things will still resolve correctly?
I believe that the Google Closure compiler effectively fakes a dependency system for you in both development and production mode. This makes the order that different code is included in the source irrelevant; is there something like this for React?

Note: the answer below is very outdated.
I stopped using RequireJS a long time ago due to the fact that it gets rather slow in development because doesn’t bundle JS in a single file in development.
These days I’m mostly using Webpack.
You may also consider other bundlers such as Browserify and Rollup.
I use ES modules as the module system, transpiled by Babel into CommonJS. Eventually I plan to swich to ES modules completely as more bundlers with its first-class support, such as Rollup and Webpack 2, become mainstream.
Old Answer
To my knowledge, React itself doesn't provide any dependency management system; if you need one, you must use some existing tool that fits your workflow.
Personally, I'm happy using RequireJS with AMD sugar syntax so my modules look like this:
/** #jsx React.DOM */
/* jshint trailing:false, quotmark:false, newcap:false */
define(function (require) {
'use strict';
var React = require('react'),
_ = require('underscore'),
JoinWidget = require('common/views/join_widget');
var LoginWidget = React.createClass({
// ...
});
});
Each React view, as any other class, gets its own file.
This is fine in development environment but I don't want to load scripts on the fly in production, so I use grunt-requirejs task with almond to concatenate files in proper order so they are always loaded synchronously in a single file.

Related

What exactly is a "webpack module" in webpack's terminology?

I am a newbie to webpack and currently trying to understand basic concepts.
Looking at the official docs, on the page Concepts it uses module term and gives link to read more about modules on page Modules.
So on this page we have question "What is a module" but no explicit answer to that is given. Rather, it describes modules by how they "express their dependencies":
What is a webpack Module
In contrast to Node.js modules, webpack modules can express their
dependencies in a variety of ways. A few examples are:
An ES2015 import statement
A CommonJS require() statement
An AMD define and require statement
An #import statement inside of a css/sass/less file.
An image url in a stylesheet url(...) or HTML file.
So it doesn't explicitly defines what exactly is the module and I am confused now.
Is module just a javascript file?
Or is it any type of file like .css or images?
Or is module some logical concept not related to physical files at all?
The simple answer to your question is that a Webpack Module is a Javascript file that is processed by Webpack.
As for why that's a thing, well, consider the following Javascript:
if (window.matchMedia('(max-width: 600px)')) {
const img = document.querySelector('#header-responsive-image');
img.src = 'different/image/url/file.jpg';
img.classList.add('some-class');
}
Note that this code has dependencies on specific markup, image files, and CSS rules. But crucially you have to read the code to find out what they are. There's no (easy) way to statically analyze the dependencies (or even do it by hand!).
This may not seem like a big deal in small apps, but when you're working with a large Javascript codebase or authoring a component library, the ability to statically analyze the real dependency graph and have your tools warn you immediately when your JS, CSS, markup, and files on disk get out of sync is a lifesaver.
With Webpack at the top of the file you're going to see something more like this:
import header600Width from '../img/header-600-width.jpg';
import '../styles/has-some-class.css';
// etc.
You can load images, csv, xml, toml, json, css, and the list goes on. This is something that other modules systems by-and-large can't or won't do. So a Webpack module is, in a sense, a superset of a Javascript module.

Ember why do we have to use import for certain bower dependencies

In an Ember app, when using certain dependencies like moment installed via bower, we have to also import the same in the ember-cli-build.js file:
app.import('bower_components/moment/moment.js');
My question is why is that needed, since I would assume everything inside node_modules as well as bower_components should be available for use inside the app.
Also if that is not the case, how do we identify which dependencies would require such explicit import to be able to use them ?
You don't have to, actually.
There is a package now that lets you 'just import' things: https://github.com/ef4/ember-auto-import
Some reading on the topic of importing: https://discuss.emberjs.com/t/readers-questions-how-far-are-we-from-being-able-to-just-use-any-npm-package-via-the-import-statement/14462?u=nullvoxpopuli
In in-depth answer to your question and the reasons behind why things are the way they are is posted here:
https://discuss.emberjs.com/t/readers-questions-why-does-ember-use-broccoli-and-how-is-it-different-from-webpack-rollup-parcel/15384?u=nullvoxpopuli
(A bit too long for stack overflow, also on mobile, and I wouldn't want to lose all the links and references in a copy-paste)
Hope this helps
Edit:
To answer:
I just wanted to understand "in what cases" do we need to use the import statement in our ember-cli-build (meaning we do not do import for all the dependencies we have in our package/bower.json)...But only for specific ones...I wanted to know what is the criteria or use case for doing import.
Generally, for every package, hence the appeal of the auto-import and / or packagers (where webpack may be used instead of rollup in the future).
Though, it's common for ember-addons to define their own app.import so that you don't need to configure it, like any of these shims, specifically, here is how the c3 charting library is shimmed: https://github.com/mike-north/ember-c3-shim/blob/master/index.js#L7
Importing everything 'manually' like this is a bit of a nuisance, but it is, in part, due to the fact that js packages do not have a consistent distribution format. There is umd, amd, cjs, es6, etc.
with the rollup and broccoli combo, we need to manually specify which format a file is. There are some big advantages to the rollup + broccoli approach, which can be demonstrated here
and here
Sometimes, depending on the transform, you'll need a "vendor-shim".
These are handy when a module has decided it wants to be available on the window / global object instead of available as a module export.
Link: https://simplabs.com/blog/2017/02/13/npm-libs-in-ember-cli.html
(self represents window/global)
however, webpack has already done the work of figuring out how to detect what format a js file is in, and abstracts all of that away from you. webpack is what ember-auto-import uses, and is what allows you to simply
import { stuff} from 'package-name';. The downside to webpack is that you can't pipeline your transforms (which most people may not need, but it can be handy if you're doing Typescript -> Babel -> es5).
Actually: (almost) everything!
Ember does, by default, not add anything to your app except ember addons. There are however some addons that dynamically add stuff to your app like ember-browserify or ember-auto-import.
Also just because you do app.import this does not mean you can use the code with import ... from 'my-package'. The one thing app.import does is it adds the specified file to your vendor.js file. Noting else.
How you use this dependency depends completely on the provided JS file! Ember uses loader.js, an AMD module loader. So if the JS file you app.imported uses AMD (or UMD) this will work and you can import Foo from 'my-package'. (Because this is actually transpiled to AMD imports)
If the provided JS file provides a global you can just use the global.
However there is also the concept of vendor-shims.. Thats basically just a tiny AMD module you can write to export the global as AMD module.
However there are a lot of ember addons that add stuff to your app. For example things like ember-cli-moment-shim just exist to automagically add a dependency to your project. However how it's done completely depends on the addon.
So the rule is:
If its an ember addon read the addon docs but usually you shouldn't app.import
In every other case you manually need to use the library either by app.import or manual broccoli transforms.
The only exception is if you use an addon that tries to generically add dependencies to your project like ember-browserify or ember-auto-import

Packaging sub-modules with rollup for node

I have a library (ES6) which is composed on many sub-modules, say
- package.json
- lib
- my_package
- file1.js
- file2.js
- sub_module1
- file3.js
- file4.js
I currently do imports like this (all inside my package - using file resolution to find, not node_modules resolution):
import {func1} from 'lib/my_package/file1'
import {func3} 'lib/my_package/sub_module1/file3'
So, in practice I have many files across sub-directories.
I am now trying to package and publish my library, which will be installed under node_modules.
It seems to me that the node resolution algorithm (when behind node_modules) only allows for a single entry point (and there is nothing rollup can do about that)
I would like to be able to include many sub directories and files and for them to be resolved individually.
As far as I understand I have to include a single toplevel file that has all the export from machinery. I can only import that single top level file.
This means having to manually create that file. It also means losing the all the sub-module name structuring that comes from the directory structure.
I was wondering: is there any way one can import any other file from a node_module directly?
Node's resolution algorithm only resolves the first part of a module source, so if someone does this...
var foo = require('your-library/subdir/foo.js');
...then Node (or Browserify/Webpack/rollup-plugin-node-resolve) will correctly resolve that to
/path/to/project/node_modules/your-library/subdir/foo.js
The tricky part is that you want to author JavaScript modules, but if someone is using your library in Node then they need CommonJS modules. Rollup can't help you here — you would need to do a one-to-one ESM->CJS conversion for each module. So that means either using Babel, or authoring CommonJS modules in the first place.

How can I bundle JavaScript files under /vendor in an ember-cli project?

Let's say I have an ES6 library "foo" under my /vendor directory in an EmberJS project constructed using the latest ember-cli (at the time of this writing 2.4.3). Assume that foo is a library with multiple files, e.g. bar.js, baz.js, etc. and they all export something.
I would like to take vendor/foo/bar.js, vendor/foo/baz.js, etc. and bundle them into a distribution file, e.g. vendor/foo/dist/foo-bundle.js that I can then import into Ember with:
app.import("vendor/foo/dist/foo-bundle.js");
This appears like it should be possible with a bundler and/or transpiler (like Babel), but it isn't clear to me what tools I should use and in what combination. Does Ember have a built in tool for doing what I want through ember-cli (if it does, I must be blind)? Should I be using an external bundler like webpack, browserify, or rollup?
In general there seems to be a lot of noise around JavaScript tooling making it difficult for me to understand what choices I have for this problem and how to properly leverage them. Any assistance would be greatly appreciated.
Some notes that may be helpful...
I have tried a few things, so far:
I have tried just importing the main.js file, in hopes that EmberJS would also walk the dependency tree and import any other files that were referenced in import statements. This only imported the main.js file and no other dependencies.
I've looked at broccoli-es6modules and had errors when running it, but it also uses esperanto which is deprecated in favor of rollup.
I've also tried using rollup directly, with a minor degree of success, but often times my bundle.js output is empty and doesn't include the code from bar.js or baz.js because I've only imported them in the entry point (e.g. main.js):
main.js
-------
import bar from './bar.js';
import baz from './baz.js';
bar.js
------
export default function bar() {
...
}
baz.js
------
export default function baz() {
...
}
I have found if my main.js includes a function that calls either code from bar or baz I get more than an empty bundle, but if foo is just a collection of scripts from a third-party vendor that have no "application entry point", aside from what amounts to something like a manifest file, rollup seems to be the wrong choice for what I'm looking for.
Thanks again!
(Updated with the latest options.)
There are a few options.
If baz.js and bar.js are your own modules and code, the best if you just place them in app/my-awesome-module folder. You can use ES6 import to import in other place, where you would like to use them. Ember CLI will transpile, concatenate and minify them automatically.
If you would like to use 3rd party modules or solutions, check out http://emberobserver.com, most of the popular library already converted to Ember Addon, so you can install them with ember install.
Use ember-auto-import in your project and import libraries as normal ES6 module like this: import MyCoolModule from "my-cool-module";

Javascript Analysis tool for code dependencies

I was wondering if there exist javascript analysis tools that analyse a bunch of javascript files and determines which javascript files depend on each other. For example:
file A:
function testObject() {
}
file B:
var test = testObject();
Then I should get that file B depends on A since B uses function testObject defined in file A. Something similar exists for node, which is madge, but I was wondering if this also exists for the described case. Madge seems to only work for javascript files that specifically use require to import the functionality.
There is a tool that will graph dependencies into an image if wanted. Hope it helps. MaDGe
Create graphs from your CommonJS, AMD or ES6 module dependencies. Could also be useful for finding circular dependencies in your code. Tested on Node.js and RequireJS projects. Dependencies are calculated using static code analysis. CommonJS dependencies are found using James Halliday's detective, for AMD I'm using amdetective and for ES6 detective-es6 is used. Modules written in CoffeeScript with extension .coffee are supported and will automatically be compiled on-the-fly.

Categories

Resources