referencing an amd module(arcgis) in webpack app - reactjs

I'm building a react app with webpack and i need to incorporate arcgis maps into a react component. I have know idea how to bring this into my project. I've tried creating an arcgis directory with an index.js of the built javascript and trying to reference that:
import {Map} from 'arcgis/index'
That doesn't work. I then just tried to include the css/js script tags directly into my index.html but when I try to require them, like in the example, webpack obviously can't find them. Is there some way to tell webpack to ignore require calls in my src file so it gets handled by the browser? I'm trying and failing at doing the following:
import React from 'react'
export default class EsriMap extends React.Component {
componentDidMount() {
const _this = this
require(["esri/map", "dojo/domReady!"], function(Map) {
var map = new Map(_this.refs.map, {
center: [-118, 34.5],
zoom: 8,
basemap: "topo"
});
});
}
render() {
return (
<div ref="map"></div>
)
}
}

You may want to try this https://github.com/tomwayson/esri-webpack-babel .
This method is nice because it doesn't bog down the build. You pull in the ESRI Api from the CDN, and tell webpack that it's an external.
//Add this...
externals: [
// Excludes any esri or dojo modules from the bundle.
// These are included in the ArcGIS API for JavaScript,
// and its Dojo loader will pull them from its own build output
function (context, request, callback) {
if (/^dojo/.test(request) ||
/^dojox/.test(request) ||
/^dijit/.test(request) ||
/^esri/.test(request)
) {
return callback(null, "amd " + request);
}
callback();
}
],
//And this to you output config
output: {
libraryTarget: "amd"
},
When your app loads you bootstrap you webpack modules using Dojo in a script tag.
<!-- 1. Configure and load ESRI libraries -->
<script>
window.dojoConfig = {
async: true
};
</script>
<script src="https://js.arcgis.com/4.1/"></script>
<!-- Load webpack bundles-->
<script>
require(["Angular/dist/polyfills.bundle.js", "Angular/dist/vendor.bundle.js", "Angular/dist/app.bundle.js"], function (polyfills, vendor, main) { });
</script>
I've got it working with an Angular 2 App I'm working on. The only downside is I haven't yet got the unit tests to run right using Karma. I've only been working on that a few hours now.. Hope to have a solution to the testing issue soon.

#getfuzzy's answer will work well as long as you don't need to lazy load the ArcGIS API (say for example only on a /map route).
For that you will want to take the approach I describe in this answer
This blog post explains why you need to use one of these two approaches and explains how they work as well as the pros/cons of each.

I think you can try using bower version of esrijsapi. Doc link

Related

Find Google Analytics object in window in conjunction with gatsby-plugin-google-analytics

I'm trying to set up event tracking with Google Analytics. I am using Gatsby and gatsby-plugin-google-analytics in my gatsby-config.js to produce this Google Analytics snippet in the head of my document.
// gatsby-config.js
{
resolve: `gatsby-plugin-google-analytics`,
options: {
trackingId: process.env.GA_TRACKING_CODE,
head: true
}
}
In the head of my document when viewing page source:
<link rel="preconnect dns-prefetch" href="https://www.google-analytics.com"/><script>
if(!(navigator.doNotTrack == "1" || window.doNotTrack == "1")) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
}
if (typeof ga === "function") {
ga('create', 'UA-XXXXXXXX-X', 'auto', {}); // tracking code commented out
}
</script>
Now according to the Google Analytics docs on events, I can leverage the analytics.js script that gets loaded with the above script to send custom events to GA. Theoretically, I can use one React's onClick event on one of my components to fire a function that sends the required data.
Ex:
export default class Header extends React.Component {
function trackCall() {
ga('send', 'event', 'Call Us', 'call', 'Call Us')
}
render() {
<button onClick={this.trackCall) href="tel:1234567890">Call Us</button>
}
The problem is that this code will give me a compilation error in gatsby: error 'ga' is not defined no-undef. I'm not sure how to define this correctly, e.i: get reference to the global GA object then call its methods.
I know GA tracking is working on my site because I've tested it in real-time. However, when I scan the network resources in the console, I can't seem to find any reference to an analytics script or resource, so although it appears to be loading, perhaps the way it is bundled with gatsby and/or gatsby-plugin-google-analytics is loading it in a way that I'm not aware of.
Ideally, I want to load the GA script and then be able to access its methods to fire tracking events from my components.
I'm aware of react-ga and have looked at some examples but would prefer to implement this without additional packages.
Thanks,
Had the same issue and found the problem using the following...
Put the following into your gastby-config.js with your Google analytics id in the tracking ids
{
resolve: `gatsby-plugin-google-gtag`,
options: {
trackingIds: [
"UA-XXXXXXXX-X"
],
pluginConfig: {
head: true,
},
},
and where you want to call window.gtag wrap it in an if defined like so
export default class Header extends React.Component {
function trackCall() {
if(window.gtag){
window.gtag('send', 'event', 'Call Us', 'call', 'Call Us')
}
}
render() {
<button onClick={this.trackCall) href="tel:1234567890">Call Us</button>
}
Gatsby in develop mode will no longer complain and will ignore the code. Then if you use gatsby build and then gatsby serve you with GA Debug chrome extension you will see it added your tag to the dataLayer.

Enabling Hot Module Replacement with Angular 2 Upgraded App

We're using the upgrade adapter to setup an Angular 1/2 Hybrid app. We're bootstrapping the app like this (As described in the Angular docs https://angular.io/guide/upgrade):
class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, ['ngApp'], { strictDi: true });
}
}
For our HMR setup, we're using Angular CLI and following these instructions https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/configure-hmr.md
The problem is that when HMR runs and tries running that bootstrap code again, it attempts to rebootstrap the Angular 1 app, which results in an error that the Angular 1 module has already been bootstrapped.
Trying to only conditionally run that code if angular 1 hasn't been bootstrapped also won't work, because while the component does refresh, it doesn't reload with the new updates.
We've resorted to something that seems to work, but is less than ideal, which is removing he angular 1 app element, and recreating it, so that the bootstrap doesn't error.
Something like this:
ngDoBootstrap() {
// reinitialize angular 1 app
var element = document.getElementById('ng-app');
let windowRef = <any>window;
if(!windowRef.appContents) {
windowRef.appContents = element.innerHTML;
} else {
document.body.removeChild(element);
element = document.createElement('div');
element.id = 'ng-app';
element.innerHTML = windowRef.appContents;
document.body.appendChild(element);
}
this.upgrade.bootstrap(element, ['ngApp'], { strictDi: true });
}
While a bit hacky, that at least seems to get the HMR working. However, because it is causing the entire angular 1 app to rebootstrap, rather than just refreshing the module that changed, this is only marginally faster than a simple livereload.
Is there any better way to rebootstrap a hybrid app to allow for HMR to work?

how to include webpack in in-browser Babel?

I am newbie to React.js. For learning purpose just I created the login page which you can find here.
In my local project also, I used the CDN for babel and react, like below.
<script src="https://unpkg.com/react#latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
I want to use one of the form validation plugin into this example. But when I tried to include this (as per the document)
import ValidateableForm from 'react-form-validate';
I am getting the following error.
Uncaught ReferenceError: require is not defined
I went through few posts and they said that I have to use webpack or Rollup or Browsify .I am not sure how to include this in to my current local project setup. Since I am not using npm (in learing I dont want to use npm)
I dont know how to include that plugin into my project
If it is already coming with external site , I cant able to figure
it out what is the issue.
Please help me to resolve the issue.
This is an old question, but at least currently, this is completely possible with conventional script tags. This article is very helpful for understanding development setup alternatives for React
In that article it details bringing in React, React-Dom, and Babel via script tags for development, like this (I'm linking to npm downloaded packages, but that isn't necessary):
<script src="/node_modules/react/umd/react.development.js"></script>
<script src="/node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="/node_modules/#babel/standalone/babel.min.js"></script>
In my case, I needed to bring in the react-notification-system plugin:
<script src="/node_modules/react-notification-system/dist/react-notification-system.min.js"></script>
(Note the use of the compiled 'dist' version)
Once that was included I was able use it like this:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.notificationSystem = new ReactNotificationSystem();
}
addNotification = event => {
event.preventDefault();
const notification = this.notificationSystem.current;
notification.addNotification({
message: 'Notification message',
level: 'success'
});
};
render() {
return (
<div>
<button onClick={this.addNotification}>Add notification</button>
<ReactNotificationSystem ref={this.notificationSystem} />
</div>
);
}
}
I had to look in the plugin's code to know that the name: ReactNotificationSystem would be available, much of the plugin documentation that you find is not written with this type of dev setup in mind, but it does work.

How can I render the react app with redux using the ReactJS.NET?

I have created the Single page application where I have used the React, Redux and React-Router.
I want to render this SPA using ReactJS.NET for improve perfomance of loading the application.
The SPA is compiled as one Bundle.js using Webpack.
I have an ASP.NET MVC application where I can paste this bundle which will be rendered through the ReactJS.NET. Everything in this SPA will be worked in one ASP.NET view but with the React-router.
How can I do that? I can't find any project where is solved this combination with redux.
Thank you for the example or help.
I know this is an old question but if you're still having issues incorporating your React app into React.NET you should try the following template and have a look at how this fellow has done it.
He uses webpack to first build and compile a server specific set of code then pulls the compiled js into React.NET
app.UseReact(config =>
{
config
.SetLoadBabel(false)
.AddScriptWithoutTransform("~/js/react.server.bundle.js");
});
The webpack config looks like this.
var path = require('path');
var webpack = require('webpack');
var WebpackNotifierPlugin = require('webpack-notifier');
module.exports = {
entry: {
server: './React/server.jsx',
client: './React/client.jsx',
clientWithRender: './React/clientWithRender.jsx',
},
output: { path: __dirname + '/wwwroot/js/', filename: 'react.[name].bundle.js' },
module: {
loaders: [
{
test: /.jsx?$/,
loader: "babel-loader",
exclude: /node_modules/,
query: {
presets: ['es2015', 'react'],
plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
}
}
]
},
plugins: [
new WebpackNotifierPlugin()
]
};
And heres the index
#{
Layout = null;
}
<html>
<head>
<title>Hello React</title>
</head>
<body>
<div id="app">
#{
if (Environment.GetEnvironmentVariables()["ASPNETCORE_ENVIRONMENT"].ToString() != "Development")
{
#Html.React("ReactComponents.App", new { val1 = "Top text" });
}
}
</div>
#{
if (Environment.GetEnvironmentVariables()["ASPNETCORE_ENVIRONMENT"].ToString() != "Development")
{
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.min.js"></script>
<script src="#Url.Content("~/js/react.client.bundle.js")"></script>
#Html.ReactInitJavaScript()
}
else
{
<script src="#Url.Content("~/js/react.clientWithRender.bundle.js")"></script>
}
}
</body>
</html>
Why use ReactJS.NET? There is nothing special about an MVC.NET stack which requires a separate project to get React up and running in it. I would use a combination of Babel, Webpack, React, React-Dom and React-Router instead. MVC.NET should just deliver the bundle everything else should be react and it's dependencies.
The problem with the default tutorial of React.NET is that it does not consider the fact you are using webpack to bundle your dependencies and instead has examples of adding them manually. This is not really the preferred way of writing React and makes a complicated process even more complicated by trying to hide away the initial complexity of setting up your React project.
Suggestion:
Webpack will bundle your react-router, react and react-dom amongst other stuff. You need MVC to be setup in a way that every url request is handled by the same controller action that way React-Router can handle the url changes. This answer explains how to do this. ASP.NET MVC - Catch All Route And Default Route
Without doing this, MVC will try to handle all url route changes instead of React-Router doing it's thing.

Using RequireJS with AngularJS. Problems loading AngularJS

I am creating a NodeJS app which uses AngularJS for it's front-end. I am Also using RequireJS to load in the JS dependencies and then instantiate the Angular app. Here is what I am trying to do:
Within my HTML file (written in Jade) I include the RequireJS files and then call the RequireJS config using the 'data-main' attribute:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
script(type="text/javascript" src="/bower_components/requirejs/require.js" data-main="/main.js")
My main.js file looks as follows:
"use strict";
function(require) {
require(['/assets/requiredPathsAndShim.js'], function(requiredPathsAndShim) {
require.config({
maps : {
// Maps
},
paths : requiredPathsAndShim.paths,
shim : {
// Modules and their dependent modules
}
});
angular.bootstrap(document, ['appNameInHere']);
});
})(require);
I have an external file which contains an object with my routes '/assets/requiredPathsAndShim.js' and it looks like follows:
"use strict";
(function(define) {
define([], function() {
return {
paths : {
'angular' : '/bower_components/angular/angular'
}
};
});
})(define);
I will add that my NodeJS/Express app has the 'bower_components' folder set to serve static files and this is working fine.
Whenever I try and instantiate the AngularJS app using the 'angular.bootstrap...' method it tells me Angular is not defined. I can't see why this is happening and haven't been able to figure it out yet. O can't see any problem with my routes to the Angular files. Can anyone see or suggest why this may be happening?
Thanks!
Just managed to crack it! I had to place the 'angular.bootstrap' call in a callback function of the require.config method as the app was trying to call AngularJS before it had been defined.
Hope this helps anyone in the future.

Resources