AngularJS and Require: r.js gives undefined - javascript

I understand there's some debate about whether or not to use require.js with AngularJS, but I am doing so at this time. I have the whole project set up and running with require, and am now attempting to use r.js to optimize and minify.
After running r.js and changing my data-main in my index.html file, I am now getting that angular is undefined and cannot proceed.
I was able to reproduce the same behavior using the angular-require-seed. I followed the instructions on github to install and then made the following build definition for r.js.
build.js
({
baseUrl: "./app/js",
name: "main",
out: "index-built.js",
paths: {
angular: '../../bower_components/angular/angular',
'angular-scenario': '../../bower_components/angular-scenario/angular-scenario',
'angularRoute': '../../bower_components/angular-route/angular-route',
'angular-mocks': '../../bower_components/angular-mocks/angular-mocks'
}
})
I then ran r.js using the following command at the top level of the app.
r.js.cmd -o build.js
Once r.js completed I changed the data-main in index.html to be data-main="index-built.js"
This is once again resulting in angular being undefined. Can anyone point me to the error of my ways?

Are you remembering to shim the library?
If you are then you will also need to include that same config in your build.js. The best way to do this is point the mainConfigFile property at your main.js and let it pick up the config values from there (including the paths above too).

Related

Can I use unpkg or browserify to include single NPM packages in a frontend project?

So I'm working with JS on the frontend, building something for a client. Details aren't super important except that I do not have access to node.
I'm using unpkg to include various NPM packages in the browser (like React/ReactDOM/Babel for instance). These packages have a UMD build so they work out of the box.
However, there are a few packages I'd like to use that do not have a UMD build (namely react-dates or react-datepicker). I've tried serving different files via unpkg and referencing the exported modules. Since they don't have UMD builds, I'll either get an error module is not defined which makes sense, or that the module I'm referencing DatePicker is not defined.
So I thought maybe I could build a single file with browserify but I've never used it before and any docs I could find are lacking. Heres what I did
var DatePicker = require("react-dates");
In a file called test.js and then:
browserify test.js -o bundle.js
Output that, upload it to the client assets, reference it like:
<script src="/js/bundle.js"></script>
But var DatePicker = require("DatePicker") throws error require is not defined (I thought that was the point of browserify?) and console.log(DatePicker) throws is not defined as well.
At this point I'm at a loss. I'm being stubborn but I really really just want to use a react datepicker and avoid adding jQuery to this project for the sole purpose of a datepicker. As far as I can tell unpkg is not an option but I feel like browserify could work and I'm just doing something wrong.
Any help is greatly appreciated!
You don't have to do this, you can find the needed files in the dist folder (New folder\node_modules\react-datepicker) after you "npm install react-datepicker" within a folder, but be sure you have a package file into that, otherwise the install won't work.
The files should look like this
EDIT:
The requirejs code that you need is
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.2/require.min.js"></script>
<script>
requirejs.config({
paths: {
'react': 'https://unpkg.com/react#15.3.2/dist/react',
'react-dom': 'https://unpkg.com/react-dom#15.3.2/dist/react-dom',
'prop-types': 'https://unpkg.com/prop-types#15.6.0/prop-types',
'react-onclickoutside': 'https://unpkg.com/react-onclickoutside#6.7.0/dist/react-onclickoutside',
'react-popper': 'https://unpkg.com/react-popper#0.7.4/dist/react-popper',
'moment': 'https://unpkg.com/moment#2.19.3/moment',
'datepicker': 'https://unpkg.com/react-datepicker#0.61.0/dist/react-datepicker'
}
});
requirejs(['react', 'react-dom', 'prop-types', 'react-onclickoutside', 'react-popper', 'moment', 'datepicker'], function(React, ReactDOM, PropTypes, onClickOutside, Popper, moment, DatePicker) {
ReactDOM.render(
React.createElement('p', {}, 'Hello, World!'),
document.getElementById('root')
)
});
but as far as I got, datepicker requested for "module" which is not defined, this can be the same problem as here. I will investigate more about this issue.

Require third party RequireJS modules with Webpack

I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';

webpack 1: resolve.alias not aliasing one npm module to another

I have a webpack config used to create a server bundle for an isomorphic React app. Inside of that config, I’m trying to use resolve.alias to alias one module (parse) as another (parse/node). This handy chart about resolve.alias in webpack's documentation makes it seem like this should be possible. This is what my alias object looks like:
alias: {
parse: 'parse/node',
pubnub: 'static/deps/pubnub/pubnub-3.13.0.min.js'
}
I’m already using alias for the module pubnub, and that alias works at intended. Unfortunately, whatever I do to the parse key doesn’t seem to change the resulting require in my webpack-built bundle.js:
/***/ function(module, exports) {
module.exports = require("parse");
/***/ },
I’m trying to resolve to /node_modules/parse/node.js. Using absolute/relative paths doesn’t seem to work, nor added a .js extension to the end. At this point, I can’t figure out if this is a webpack bug or something I’m overlooking. Any help would be greatly appreciated! Here’s a link to a gist with my full webpack config: https://gist.github.com/daleee/a0025f55885207c1a00a
node#5.7.0
npm#3.7.5
webpack#1.12.14
The issue was with the following line in the webpack configuration:
...,
externals: [nodeExternals({
whitelist: ['webpack/hot/poll?1000']
})],
...,
webpack-node-externals is a webpack plugin that is used to automatically blacklist modules found in node_modules. There is usually no need to bundle npm modules in with your final bundle when building for the backend, as the npm modules are installed on the system. This blacklist also prevented webpack from doing any aliasing to any npm modules. Changing the whitelist array like so solved my issue:
...,
externals: [nodeExternals({
whitelist: ['webpack/hot/poll?1000', 'parse']
})],
...,
The moral of this story: don't copy code from boilerplates without fully understanding what it does. I could have saved a few days of headache if I had simply just read the README.md for the webpack plugins I was using.

"Uncaught ReferenceError: require is not defined" with Angular 2/webpack

I am working an HTML template from a graphic design company into my Angular 2 project using node and webpack.
The HTML pulls in various scripts like this:
<script src="js/jquery.icheck.min.js"></script>
<script src="js/waypoints.min.js"></script>
so I am requiring them in my component.ts:
var icheckJs = require('../js/jquery.icheck.min');
var waypointsJs = require('../js/waypoints.min');
There are several other scripts too and some SASS which appears to be working correctly.
webpack is happy and build it all and an 'npm start' is successful too. However, when it reaches the browser, I get this complaint:
Uncaught ReferenceError: require is not defined node_modules/angular2/platform/browser.js:1 Uncaught ReferenceError: require is not defined
which is actually thrown by this line from url.js:
var punycode = require('punycode');
Is this a CommonJs require? I hadn't used this in web development before a few weeks ago so I'm still untangling the various requires from webback, CommonJs et at.
An extract from my webpack.config.js for the .js loader looks like this:
{ test: /\.js$/, loader: 'script' }
How do I work around this error?
WebPack can do this alone. You need to make sure you load the initial chunk first using a script src tag. It will typically be the value of the entry: key in the WebPack config with -bundle appended. If you're not doing explicit chunking, your entry chunk should be both an initial and entry chunk and have the WebPack runtime in it. The WebPack runtime contains and loads the require function before your code runs.
Your components or whatever you're requiring need to be required from the entry file since your scripts will start there. Basically, if you're not explicitly chunking, the entry point JS file is the only one you can include with script src. Everything else needs to be required from it. What you include will typically have bundle in the JS filename. By default, it should be main-bundle.js.
For anyone that is looking for an answer but the above doesn't work:
Short
Add or Replace current target in webpack.config.js to target: 'web'
A bit longer
Webpack has different targets, if you've experimented with this and changed your target to node it will use 'require' to load chuncks.
The best thing is to make your target (or to add) target: 'web' in your webpack.config.js. This is the default target and loads your chuncks in a way the browser can handle.
I eventually found this solution here.
You can do this in one line assumed that you have
the bundle in dist/bundle.js
the source file client code that will render the page in the browser in
client/client.js
webpack && webpack ./client/client.js dist/bundle.js \
&& webpack-dev-server --progress --color
You need to run webpack again since if some sources in the library change you will get the last changes then in the dist/bundle.js package (of course you can add like a grunt file watch task for this). webpack-dev-server will run the server then.

Dynamic requirejs configuration extending

I'm using requirejs for multipage project. Each page is an App. All of the apps have some common dependencies, i.e. jquery, backbone, underscore etc.
I want to move all this dependencies to the one single file.
That's how the js folder structure looks like:
js
base-app-require-configuration.coffee
app
homepeage
init.coffee
build.js
application.coffee
app1
init.coffee
build.js
application.coffee
app2
init.coffee
build.js
application.coffee
Homepage application example:
js/base-app-require-configuration.coffee
define ->
requirejs.config
urlArgs: "bust=#{ new Date().getTime() }"
# yep, tricky paths here
paths:
jquery: '../../jquery.min'
underscore: '../../underscore-min'
backbone: '../../backbone.min'
js/app/homepage/init.coffee
define [
'../../base-app-require-configuration'
], (
baseRequireConfig
) ->
requirejs.config
paths:
'jquery.alphanum': '../../jquery.alphanum'
shim:
'jquery.alphanum':
deps: ['jquery']
require [
'jquery'
'application'
], (
$
Application
) ->
$ -> new Application
js/app/homepage/build.js
({
mainConfigFile: ['../../base-app-require-configuration.js', 'init.js'],
wrapShim: 'true',
baseUrl: './',
name: 'init',
findNestedDependencies: true,
out: 'init.js'
})
My data-name is init.js
The thing works pretty well for multiple apps with the common dependencies moved to one sigle file - base-app-require-configuration.coffee, except one thing: the only way to compress/optimize this using r.js is to set the flag findNestedDependencies to true, because otherwise r.js won't see requirejs.config calls nested into define/require.
My questions are:
Is using findNestedDependencies a good practice?
Is there a prettier way to organize my dependencies without repeating?
If there is such a way - will it be compatible with r.js?
Let me share this solution with you.
I'm also looking for the similar solution with requirejs (how to organize the multipage project without repetitions of a long configuration, with a "shim" feature), and I have found the following one (I would be glad if this snippet can help you):
Inside HTML:
...
<script src="js/lib/require.js"></script>
<script>
//Load common code that includes config, then load the app
//logic for this page. Do the requirejs calls here instead of
//a separate file so after a build there are only 2 HTTP
//requests instead of three.
requirejs(['./js/common'], function (common) {
//js/common sets the baseUrl to be js/ so
//can just ask for 'app/main1' here instead
//of 'js/app/main1'
requirejs(['app/main1']);
});
</script>
...
where "common.js" contains the common configuration of requirejs for your project. This sample is from: https://github.com/requirejs/example-multipage-shim/blob/master/www/page1.html.
The full code of a sample project is here: https://github.com/requirejs/example-multipage-shim. The sample "build.js" file also providen, I see there is no necessity in "findNestedDependencies" in this case.
Sure, there is a bit more code inside HTML, but I think this is not significant downside.
Is using findNestedDependencies a good practice?
Not sure. the only thing i know, is that this option can slow down the bundling process quite a lot:
Is r.js dependency tracing significantly slower since v2.1.16? Or is it just me?
Is there a prettier way to organize my dependencies without repeating?
If there is such a way - will it be compatible with r.js?
this is a great article out organising backbone modules using r.js:
https://cdnjs.com/libraries/backbone.js/tutorials/organizing-backbone-using-modules

Categories

Resources