Thursday, June 15, 2017

MERN Series Step 7 - Job models and components


Ok, finally got past the stupid webpack issue that was causing a complete gulp fail.  You need to add one more require at the top, and modify the webpack task:
const path = require('path');

gulp.task('webpack', cb => {
webpack({
entry: './app/scripts/webpack.js',
output: {
path: path.resolve(__dirname, '.tmp/scripts/'),
filename: 'bundle.js',
},
}, (err, stats) => {
if (err) {
throw new gutil.PluginError('webpack', err);
}
cb();
});
});

However, there would need to be lots of modifications to my gulpfile.js, so I'm just going to go with the one from the mern framework from techdojo, start up your server using gulp serve and you're off and running with a lovely MERN page

Configure your eslint to work with react:

Something I'm not fond of with this framework at the moment, but this may be in place for server side rendering for search engines or something, but you have to have routes defined on both the server and the client in order to enable both navigation by clicking, or by entering the URL into the browser.  I stumbled on this after creating a new route in /app for my jobs list, but not putting the route in the server, I could get to the page by clicking the link/button, but not entering the URL.

I'm moving on to create back end models in the server code and front end components to display and edit Jobs since what I really want to do with this is learn React and I've not been doing much of that so far, just mucking with Auth0.  I'll finish up the setup for Auth0 once I've got some basic React components and server models set up before doing searching or any more complicated stuff with React.

The yomern yo generator looks like it does a nice job setting up a basic CRUD module both server and app, so  I'll be going with that to create my Jobs module.

C:\Repos\mern [master ≡ +0 ~10 -0 !]> yo yomern
Hello There Fellow MERN User
? What is your module name? Job
? Would you like to generate a new CRUD component ? Yes
Add the front-end routes for the module in app.jsx, add the backend-routes in routeHelper.js, require the backend-route file in the express.js file and require the model in server.js file
? Add a field name to the model Id
? Would you like to add another field name to the model? Yes
? What is your other field name? Description
   create app\components\jobs\CreateJob.jsx
   create app\components\jobs\EditJob.jsx
   create app\components\jobs\ViewJob.jsx
   create app\components\jobs\ViewJobChild.jsx
   create app\components\jobs\ListJobs.jsx
   create app\components\jobs\ListJobsChild.jsx
   create app\components\jobs\Form.jsx
   create app\stores\JobStore.jsx
   create server\models\Job.js
   create server\controllers\jobs.server.controller.js
   create server\routes\job.server.routes.js
C:\Repos\mern [master ≡ +5 ~10 -0 !]>

So, this was very convenient, it generated classes for both the client side app and the server side app, creating basic crud templates, routes, and models with the properties I entered.  I would recommend not calling one of the fields Id, it generates an _id field for you, so I went through and renamed my Id field to Title, I had to touch the jsx files for Create, Form, ListJobsChild, and ViewJobsChild, and server side it was just the Jobs.js in the models.  These are also the files you would have to modify in order to add additional properties.  While the generator does create the server side routes file for you, it does not add it to your routerHelper.js, this should be as easy as copy/paste/rename from one of the sets of routes already in there.  You will also need to set up your routes on the client side in App.jsx, again, copy/paste/rename, really easy.

Saturday, May 20, 2017

MERN Series Step 6 - Auth0 with Tech-Dojo

With the copying of files from the create-react-app auth0 scripts our tech-dojo mern app still runs fine, and the tests all run as well, except for the one that was failing at the start (1) should fail to save an existing user again).  Don't forget to have mongodb running for the unit tests.
Now we'll wire up the auth0 login/signup instead of the login/signup that is in the tech-dojo starter.  Step 1, add the login component from auth0 to app/components/App.jsx by inserting import Login from './auth/Login.js'; to the bottom of the imports section.  Step 2, add a route so we can get to the login component, the routes section should be pretty obvious, it has about 10 lines starting with <Route …>, so I'm adding         <Route path="/login" component={Login} /> to the bottom of that.  Now lets open the site and see what happens.

Hmm, ok, middle of the page is missing content, and the dev tools console says:

app\components\App.jsx:33 Uncaught ReferenceError: Login is not defined
    at new exports.default (app\components\App.jsx:33)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:148)
    at ReactCompositeComponentWrapper.wrapper [as mountComponent] (ReactPerf.js:66)
    at Object.mountComponent (ReactReconciler.js:37)
    at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:225)
    at ReactCompositeComponentWrapper.wrapper [as mountComponent] (ReactPerf.js:66)
    at Object.mountComponent (ReactReconciler.js:37)
    at mountComponentIntoNode (ReactMount.js:266)
    at ReactReconcileTransaction.perform (Transaction.js:136)
    at batchedMountComponentIntoNode (ReactMount.js:282)

Ok, so looking closer at /app/components/auth/login.js I see:
import {login} from '../auth';
So it looks like I moved the auth.js file one folder to high, so move it from the apps folder to the components folder.

After the move, now I get this in the console:
C:/Repos/mern/app/components/auth.js: Unexpected token (67:10) while parsing file: C:\Repos\mern\app\components\auth.js
  65 | export function connectProfile(WrappedComponent) {
  66 |   return class ProfileContainer extends Component {
> 67 |     state = {
     |           ^
  68 |       profile: null
  69 |     };
  70 |

Ok, no idea here what's going on.  Taking a step back and going to make sure the create-react-app with auth0 customizations that I started from is working, and it appears that it's not, so I'm going to get that working first and hopefully that will either solve my issues or point me in the right direction.  Looking at the generic create-react-app w/o the auth0 additions and that works fine, so I have likely missed something I need to do to enable auth0 to work.

Running the base auth0 app and I'm getting this:
warning.js:36 Warning: Failed prop type: The prop `history` is marked as required in `Router`, but its value is `undefined`. in Router (at App.js:12) in App (at index.js:7)
After hunting through the results in google, looks like react-router has changed significantly since the auth0 scripts were created, they should probably have that pinned to ^3.0.5 until they update the routes to be 4.x compliant.  To get it running I had to update packages.json to use
    "react-router": "^3.0.5"
And remove the entry for react-router-dom (it's only for 4.x version of react-router).  Once that change was made make sure your server isn’t running, do npm i and restart your server and it should work.  One other thing to note, when you're putting your client key and domain in, make sure you remove the curly braces, that's not evident until you look at the errors in the console.

So, now with my base auth0 react-app running fixing the tech-dojo version should be easy. Still getting this error:
C:/Repos/mern/app/components/auth.js: Unexpected token (67:10) while parsing file: C:\Repos\mern\app\components\auth.js
  65 | export function connectProfile(WrappedComponent) {
  66 |   return class ProfileContainer extends Component {
> 67 |     state = {
     |           ^
  68 |       profile: null
  69 |     };
  70 |

Update dependencies in package.json, several missing or out of date:
  "dependencies": {
    "async": "^1.5.0",
    "auth0-lock": "^10.14.0",
    "babel": "^6.0.0",
    "babel-core": "^6.2.1",
    "babel-loader": "^6.1.0",
    "babel-preset-es2015": "^6.1.2",
    "babel-preset-react": "^6.1.2",
    "babelify": "^7.2.0",
    "body-parser": "^1.12.4",
    "connect-mongo": "^1.0.2",
    "cookie-parser": "^1.4.0",
    "cors": "^2.6.0",
    "dotenv": "^4.0.0",
    "ejs": "^2.3.1",
    "events": "^1.1.1",
    "express": "^4.15.2",
    "express-jwt": "^5.3.0",
    "express-session": "^1.15.2",
    "glob": "^6.0.1",
    "guid": "0.0.12",
    "gulp-uglify": "^1.5.3",
    "history": "1.17.x",
    "jquery": "^2.1.4",
    "jwt-decode": "^2.2.0",
    "lodash": "^3.10.1",
    "mongoose": "4.0.3",
    "node-jsx": "^0.13.3",
    "nodemailer": "^1.10.0",
    "object.assign": "4.0.3",
    "passport": "^0.3.2",
    "passport-auth0": "^0.6.0",
    "passport-local": "^1.0.0",
    "react": "^15.5.4",
    "react-bootstrap": "^0.28.1",
    "react-dom": "^15.5.4",
    "react-router": "^3.0.5",
    "react-router-bootstrap": "^0.20.1",
    "react-slick": "^0.9.3",
    "react-tools": "^0.13.3",
    "reactcss": "^0.4.2",
    "reactify": "^1.1.1",
    "source-map": "^0.5.2",
    "vinyl-buffer": "^1.0.0",
    "vinyl-source-stream": "^1.1.0"
  },
 and run npm I to install them

And we still get this:
C:/Repos/mern/app/components/auth.js: Unexpected token (67:10) while parsing file: C:\Repos\mern\app\components\auth.js
  65 | export function connectProfile(WrappedComponent) {
  66 |   return class ProfileContainer extends Component {
> 67 |     state = {
     |           ^
  68 |       profile: null
  69 |     };
  70 |

So, integrating the auth0 scaffolding from create-react-app may not be the way to go, not sure but there may be something in there dependent on what react-scripts does.  I'm going to look at pulling in the code from the 01-login example from auth0 that doesn't use create-react-app.

Insert these transforms after the babelify tranform:
    .transform("brfs")
    .transform("ejsify")
    .transform("reactify")

You'll need to add brfs and ejsify to your package.json also
Npm I --save-dev brfs
Npm I --save-dev ejsify

Now I'm getting:
[08:03:41] WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.output.path: The provided value ".tmp/scripts/" is not an absolute path!
    at webpack (C:\Repos\ItSideJobs\web\node_modules\webpack\lib\webpack.js:19:9)
    at Gulp.gulp.task.cb (C:\Repos\ItSideJobs\web\gulpfile.js:36:3)
    at module.exports (C:\Repos\ItSideJobs\web\node_modules\orchestrator\lib\runTask.js:34:7)
    at Gulp.Orchestrator._runTask (C:\Repos\ItSideJobs\web\node_modules\orchestrator\index.js:273:3)
    at Gulp.Orchestrator._runStep (C:\Repos\ItSideJobs\web\node_modules\orchestrator\index.js:214:10)
    at Gulp.Orchestrator.start (C:\Repos\ItSideJobs\web\node_modules\orchestrator\index.js:134:8)
    at C:\Users\David\AppData\Roaming\npm\node_modules\gulp\bin\gulp.js:129:20
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)
    at Module.runMain (module.js:606:11)

Saturday, April 22, 2017

"React components, do you need class to do them properly?" -or- "local state, It's a trap!"


So, I'm looking at https://facebook.github.io/react/docs/state-and-lifecycle.html and how React has leveraged the class construct and hierarchy in encapsulating the clock class in the example. I'm wondering, is the class construct necessary, and I'm very much hoping it is not. I'm going to try to re-create the example without using the class and extends and sticking with functional javascript. We already know you can use stateless functional components, but can we use local state in a functional component.

It would seem not entirely, you need a stateful component somewhere in your application. It looks like the right place for this is as close to the root of the application as you can get it, if you want to move toward having a single state atom (which looks extremely beneficial). So how can we re-write the react clock example using a stateless functional component.

<div id="container"> 
<!-- This element's contents will be replaced with your component. --> 
</div> 

function Clock(props) { 
    return <div><h1>Hello, world! </h1> <h2>It is {props.date.toLocaleTimeString()}. </h2></div> 
} 

var App = React.createClass({ 
    getInitialState: function() { 
        return { date: new Date() }; 
    }, 
    render: function() { 
        return <Clock date={this.state.date} />; 
    }, 
    componentDidMount: function() { 
        this.timerID = setInterval(() => this.setState({date: new Date()}),1000); 
    } 
}); 

 
ReactDOM.render( <App /> , 
    document.getElementById('container') 
); 


So, this gets the application state all in one place, in the App class, which we can persist or restore atomically, enabling time travel debugging and keeping us from getting in an inconsistent state. This doesn't necessarily mean you want all state in one place, just that relevant to App.

https://facebook.github.io/react/docs/state-and-lifecycle.html
https://www.safaribooksonline.com/blog/2015/10/29/react-local-component-state/
https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc

https://github.com/reactjs/redux/issues/1385

MERN Series Step 5 - Auth0 React Client Template


Reviewing the link from last time, https://auth0.com/docs/quickstart/spa/react, let's see what the create-react-app scripts get us.

This also led me to the link for the facebook create-react-app scripts: https://github.com/facebookincubator/create-react-app, I'll review and compare that as well in this article.

It looks like the create-react-app script is focused on the client side portion of the app, which makes sense, and the folder structure is somewhat different than that provided by tech-dojo's start repo (https://github.com/tech-dojo/mern, so they're all in one place).

For review, here's the structure tech-dojo gave us:

| .gitignore 
| CONTRIBUTING.md 
| favicon.ico 
| gulpfile.js 
| LICENSE 
| package.json 
| README.md 
| yarn.lock 
+---app 
| | .DS_Store 
| | index.ejs 
| | main.jsx 
| | style.css 
| | 
| +---components 
| | | App.jsx 
| | | 
| | +---articles 
| | | CreateArticle.jsx 
| | | EditArticle.jsx 
| | | Form.jsx 
| | | ListArticles.jsx 
| | | ListArticlesChild.jsx 
| | | ViewArticle.jsx 
| | | ViewArticleChild.jsx 
| | | 
| | +---core 
| | | Footer.jsx 
| | | Header.jsx 
| | | Home.jsx 
| | | Template.jsx 
| | | 
| | \---users 
| | EditUserProfile.jsx 
| | EditUserProfileChild.jsx 
| | Signin.jsx 
| | SigninChild.jsx 
| | SignOut.jsx 
| | Signup.jsx 
| | SignupChild.jsx 
| | 
| +---images 
| | | … 
| | | 
| | \---fav 
| | … 
| | 
| +---services 
| | Authentication.js 
| | 
| \---stores 
| ArticleStore.jsx 
| RestAPI_Helper.js 
| UserStore.jsx 
+---server 
| | express.js 
| | passport.js 
| | seeds.js 
| | server.js 
| | 
| +---config 
| | | config.js 
| | | 
| | \---env 
| | all.js 
| | development.js 
| | local.example.js 
| | production.js 
| | test.js 
| | 
| +---controllers 
| | | .DS_Store 
| | | articles.server.controller.js 
| | | errors.server.controller.js 
| | | users.server.controller.js 
| | | 
| | \---users 
| | users.authentication.server.controller.js 
| | users.authorization.server.controller.js 
| | users.password.server.controller.js 
| | users.profile.server.controller.js 
| | 
| +---models 
| | .DS_Store 
| | Article.js 
| | User.js 
| | 
| +---routes 
| | .DS_Store 
| | article.server.routes.js 
| | routeHelper.js 
| | users.server.routes.js 
| | 
| \---strategies 
| facebook.js 
| github.js 
| google.js 
| linkedin.js 
| local.js 
| twitter.js 
\---tests 
| article.server.model.test.js 
| article.server.routes.test.js 
| user.server.model.test.js 
\---componentTest 
article.test.jsx 
articleStore.test.jsx 
user.test.jsx 
userStore.test.jsx 

This does contain some potentially extraneous items that someone not initially learning React may not need (i.e. articles, users), and yes, I know lots of "may" in there. I am learning React, so I can't tell you that yet.

Facebook's vanilla create-react-app script gives you this structure:

| .gitignore
| package.json
| README.md
|
+---public
| favicon.ico
| index.html
|
\---src
App.css
App.js
App.test.js
index.css
index.js
logo.svg

They have a great section on why to use this for creating your app, and how to customize it in the future if you need to: https://github.com/facebookincubator/create-react-app#why-use-this. This structure seems a bit more simplistic than I'd like, having everything in the src folder, but may be good for getting something up and going quickly.

Installing the auth extensions to the facebook app using create-react-app my-app1 --scripts-version auth0-react-scripts gives the same basic structure, but at least has a components folder under src, and the addition of auth0 stuff.

| .env.example 
| .gitignore 
| package.json 
| README.md 
+---public 
| favicon.ico 
| index.html 
\---src 
| auth.js 
| index.css 
| index.js 
| logo.svg 
\---components 
App.js 
App.test.js 
EditProfile.css 
EditProfile.js 
Home.css 
Home.js 
Login.css 
Login.js 
Site.css 
Site.js 

So, I'll be sticking with my initial layout, and just copy the auth0 stuff from the components folder generated by the auth0 extensions to create-react-app into an auth folder under my components folder, so it will end up looking like this:

| +---components 
| | | App.jsx 
| | | 
| | +---articles 
| | | CreateArticle.jsx 
| | | EditArticle.jsx 
| | | Form.jsx 
| | | ListArticles.jsx 
| | | ListArticlesChild.jsx 
| | | ViewArticle.jsx 
| | | ViewArticleChild.jsx 
| | | 
| | +---core 
| | | Footer.jsx 
| | | Header.jsx 
| | | Home.jsx 
| | | Template.jsx 
| | | 
| | +---users 
| | | EditUserProfile.jsx 
| | | EditUserProfileChild.jsx 
| | | Signin.jsx 
| | | SigninChild.jsx 
| | | SignOut.jsx 
| | | Signup.jsx 
| | | SignupChild.jsx 
| | \---auth 
| | EditProfile.css 
| | EditProfile.js 
| | Login.css 
| | Login.js 

There's also an auth.js in the src folder one layer up from components that I'm copying over also. So that's going to be my basic layout with auth0, next article I'll cover anything needed to integrate and get everything running with the MERN starter project from tech-dojo.

x
x

Sunday, April 16, 2017

Learn to code deal

https://academy.sciencealert.com/sales/pwyw-learn-to-code-2017-google-go?utm_source=sciencealert.com&utm_medium=referral&utm_campaign=pwyw-learn-to-code-2017-google-go_020217&utm_term=scsf-211745

Learn to code package.  I haven't tried anything from these people, I'm going to try this one though, has a lot of languages I want to learn more about.

Friday, April 14, 2017

MERN Series Step 4 - Authentication with Auth0

https://auth0.com/docs/overview
They have a great intro video, watch it.

Our starter project already came with passport, so we'll just need to add passport-auth0 and express-session:
Yarn add passport-auth0 express-session auth0-lock


Looking at the architecture options, SPA+API looks like a natural fit to pursue: https://auth0.com/docs/architecture-scenarios/application/spa-api

You can also use the spa quickstart https://auth0.com/docs/quickstart/spa/react, that looks like it has some scripting that would be useful, I'll review that and compare in the next article.

You may also want to review JWTs as auth0 uses them, and they are beyond the scope of what I'm writing about in this series, I may get into some more detail later, but my focus with this series is not on JWTs.

First step, create a new account with the website name, then select Single Page App for the application type:

This will then present you with a sample project you can download (that will have your keys in it).  I've downloaded mine, it looks like the two files you'll need are in src/utils, with the rest of the code showing how to integrate into your app.  The .env file in the root contains your auth0 clientid and domain.  The code in src/views/Main/routes.js has examples of how to protect routes using react-router.  You can run the project itself using npm start, it just serves up a page with a login control that opens the auth0 login widget. 


Run it and try to log in and it will fail with CORS error.  Take a look at the logs for your auth0 Client (the application)


This means that we'll need to add http://localhost:3000 in order to have our sample auth0 app to connect.  Click on Clients, then on your app (mine is still "Default App") then settings, scroll down to "Allowed Origins (CORS)" and add http://localhost:3000, while you're there add http://localhost:3000/login to the "Allowed Callback URLs" area, as the sample app uses that for where auth0 sends data back to it.  Once you've done that you'll be able to login using one of the providers you've enabled (I enabled google and linked-in since this is a job board), and you should see a lovely landing page with welcoming you by name (nice!), with a logout button.

We'll take this sample app and incorporate it into our main application.  I'll be using a login widget instead of the full page layout of the auth0 sample, but beyond that we'll leave it the same.  We'll also use auth0 for authorization once we get to where we have multiple roles for our app.  Now, since we've logged into our app, you'll be able to see yourself as a user and view details.  Check it out under users:

Sunday, April 9, 2017

MERN Series Step 3 - Which client app

After looking at the two clients, one from generator-webapp and the other from tech-dojo's starter repo, I'm going to go with the app from tech-dojo, as it's structure is laid out for react components and services, vs generator-webapp is pretty generic and I'd have to do all the react setup myself.
Generator-webapp gives you an app folder with fonts, images, scripts and styles, which is fine for your generic client side app.  It also gives you a decent gulpfile to start with, and a tests folder using mocha and chai.
Tech-dojo's MERN starter gives you an app folder with components (with some examples coded, articles, core, and users), images, services, and stores, a gulpfile that I'm not familiar with yet, tests using mocha/chai/sinon with tests set up to run against the components, and you also get test coverage reporting.  On top of that you get the server folder set up to use express, mongoose, passport, and some seed data for the example components.
 
So, basically if you're reading these all in one go, skip everything I did in step one :) I'll be updating the article to reflect this new information and moving on to setting up login next using auth0, because security is hard and I don't have time to stay on top of it, and it’s their job to do so.  
Which brings me to a general point, if something is not part of your core business, don’t write it if you don't have to!  I'm not going to re-write paypal functionality if I want to take payments, nor am I going to write an email service.  Bring in something open source, or buy it if you need to, but only write it if you have to.