My JS Journey: Creating an npm Package

In this blog post, I will show how to create an npm package that can be used from other modules. The example is a wrapper around node fs.

Setting up

Start as you would for any ES6 project by creating the following. The steps are covered in previous blog postings: My JavaScript Journey: Basic ES6 CLI Skeleton and Mocha as a JavaScript Test Framework.

mkdir file-handler
cd file-handler
git init
npm init -y
mkdir src
cd src
create index.js
create _index.js
cd ..
mkdir test
cd test
create test.js
cd ..
npm install babel-core --save-dev
npm install babel-preset-env --save-dev
npm install babel-register --save-dev
npm install babel-cli --save-dev
npm install mocha --save-dev
create .gitignore
create .babelrc
cd src
update package.json to add scripts, etc.

Test fs.readFile

Add tests to test/test.js that call your wrapper method

import assert from 'assert';
import FileHandler from '../src/index';

describe('FileHandler', function() {
  const testFilesPath = 'test/data/';
  const fileName = 'hello.txt';
  let fileHandler = new FileHandler();
  describe('getData', function() {
    it('should return error when invalid path', function(done) {
      const path = "blah";
      const expected = "ENOENT: no such file or directory, open '" + path + "'";
      fileHandler.getData(path)
      .catch(function (e) {
        assert.equal(expected, e.message);
        done();
      })
      .catch(function(err) {
        done(err);
      });
    });

    it('should return file contents', function(done) {
      const expected = "hello";
      fileHandler.getData(`${testFilesPath}${fileName}`)
      .then(function(data) {
        assert.equal(encodeURI(data), expected);
        done();
      })
      .catch(function(err) {
        done(err);
      });
    });
  });
});

Add a wrapper method to src/index.js

Since the only thing you will be exporting is the FileHandler class, the code goes directly into /src/index.js. This is what will be imported by the module that uses it.

import fs from 'fs';

class FileHandler {
  getData(path, type = 'utf8') {
    return new Promise((resolve, reject) => {
      fs.readFile(path, type, (err, data) => {
        if (err) { reject(err); }
        resolve(data);
      })
    });
  }
}

export default FileHandler;

Run the test

Add a script to run the tests to package.json:

"test": "mocha --compilers js:babel-core/register test/test.js"

Run:
npm test

One test should pass and one should fail.

  FileHandler
    getData
      ✓ should return error when invalid path
      1) should return file contents

  1 passing (268ms)
  1 failing

  1) FileHandler getData should return file contents:
     Error: ENOENT: no such file or directory, open 'test/data/hello.txt'
      at Error (native)

To make the tests run automatically with each change, add the following scripts to package.json:

"start": "npm run dev",
"dev": "npm test -- -w",

To ensure you build after each change, add the following script to package.json ("pre" is a prefix that will run the script before either build or test):

"pretest": "npm run build",

And, to prevent the test file(s) from being included in the distribution, add the babel-cli flag --ignore to the build script in package.json:

"build": "babel ./src -d ./dist --ignore test.js",

Now, run:

npm start

You will see the scripts chained together. In the end, Mocha will be running, waiting for the next change to be saved. To quit, ctrl-c.


> file-handler@1.0.0 start /Users/<your source>/file-handler
> npm run dev

> file-handler@1.0.0 dev /Users/<your source>/file-handler
> npm test -- -w

> file-handler@1.0.0 pretest /Users/<your source>/file-handler
> npm run build

> file-handler@1.0.0 prebuild /Users/<your source>/file-handler
> npm run clean

> file-handler@1.0.0 clean /Users/<your source>/file-handler
> rm -rf dist

> file-handler@1.0.0 build /Users/<your source>/file-handler
> babel ./src -d ./dist --ignore test.js

src/_index.js -> dist/_index.js
src/index.js -> dist/index.js

> file-handler@1.0.0 test /Users/<your source>/file-handler
> mocha --compilers js:babel-core/register test/test.js "-w"

  FileHandler
    getData
      ✓ should return error when invalid path
      1) should return file contents

  1 passing (268ms)
  1 failing

  1) FileHandler getData should return file contents:
     Error: ENOENT: no such file or directory, open 'test/data/hello.txt'
      at Error (native)

Add test/hello.txt File

cd test
mkdir data
create hello.txt

You will need to tickle src/index.js and save it to trigger the tests to run again (or ctrl-c and start again). The test will still fail since there is no content in test/data/hello.txt.

  FileHandler
    getData
      ✓ should return error when invalid path
      1) should return file contents

  1 passing (39ms)
  1 failing

  1) FileHandler getData should return file contents:

      AssertionError: '' == 'hello'
      + expected - actual

      +hello

      at test/test.js:26:16

Add ‘hello’ to test/data/hello.txt. Tickle index.js and save it to run the tests again. All happy and green now.

  FileHandler
    getData
      ✓ should return error when invalid path
      ✓ should return file contents

  2 passing (8ms)

Checkin

This is a good spot to checkin.

Currently, my package.json looks like this:

{
  "name": "file-handler",
  "version": "1.0.0",
  "description": "Library creation demonstration",
  "main": "index.js",
  "scripts": {
    "clean": "rm -rf dist",
    "prebuild": "npm run clean",
    "build": "babel ./src -d ./dist --ignore test.js",
    "start": "npm run dev",
    "dev": "npm test -- -w",
    "pretest": "npm run build",
    "test": "mocha --compilers js:babel-core/register test/test.js"
  },
  "keywords": [
    "node",
    "fs",
    "testing",
    "mocha",
    "javascript",
    "es6"
  ],
  "author": "Ramona Ridgewell",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-core": "^6.25.0",
    "babel-preset-env": "^1.5.2",
    "babel-register": "^6.24.1",
    "mocha": "^3.4.2"
  }
}

Using the Library

We need a different app to import file-handler. How do we do that? First, to get the ES5 transpiled version of the code, change the "main" property in package.json to point to ./dist/index.js.

  "main": "./dist/index.js",

The final bit is to set which files are required by the end-user, which is the ./dist/ folder. Add this to package.json:

"files": [
  "dist"
]

Create node.js Package Module

The first step in publishing an npm module is to create the package. Navigate to the root where the package.json is. Run:

npm pack

This creates file-handler-1.0.0.tgz in the same directory. It gets the "name" field from package.json and appends the "version" from the same file, to create the file name. You can see the contents by running:

tar -tf file-handler-1.0.0.tgz

which returns:

package/package.json
package/README.md
package/dist/_index.js
package/dist/index.js

Test the Module

Create Test Module

To set up a new module, you can use this package.json or however you wish to set it up.

{
  "name": "testFileLib",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "clean": "rm -rf dist",
    "prebuild": "npm run clean",
    "build": "babel ./src -d ./dist --ignore test.js",
    "start": "npm run dev",
    "dev": "npm test -- -w",
    "pretest": "npm run build",
    "test": "mocha --compilers js:babel-core/register test/test.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-core": "^6.25.0",
    "babel-preset-env": "^1.5.2",
    "babel-register": "^6.24.1",
    "mocha": "^3.4.2"
  }
}

Add the usual src/index.js, src/_index.js, .babelrc, .gitignore. index.js doesn’t need to do anything at this point.

const main = () => {
  console.log("hello");
};

main();

Install Your Package

Here’s the most exciting part. Navigate to the root of your test project and run:

npm install ../file-handler/file-handler-1.0.0.tgz

The path assumes your library and test project are in the same parent directory —adjust appropriately. The output looks like this:

testFileLib@1.0.0 /Users/<your source>/testFileLib
└── file-handler@1.0.0

npm WARN testFileLib@1.0.0 No repository field.

If you check ./node_modules/, you will find a file-handler directory with the built /dist/, and the package.json and README.md.

Write Some Tests

I literally copied the tests from file-handler and changed line 2 to:

import FileHandler from 'file-handler';

Running npm test should just work as expected.

Read File When Running Test App

To use file-handler in index.js, change it to the following:

import FileHandler from 'file-handler';

const main = () => {
  const fileHandler = new FileHandler();
  const fileName = "test/data/hello.txt"
  fileHandler.getData(fileName)
  .then((data) => {
      console.log(data);
  })
  .catch((err) => {
    console.log("error reading file", err);
  });
};

main();

If you run:

npm test

it will clean, build and run your tests. Then, run:

node src/_index

It should say hello or whatever you put in your file.

Add file-handler to npm

At this point, even though the library only supports one method, I am going to show how to make your new library available on npm.

Add User

Assuming you have never done this before, run the following:

npm adduser

It will prompt you for Username, Password, Email. Username must be unique, so you might need to try a couple of times to find an unused one. The error begins with this:

npm WARN adduser Incorrect username or password
npm WARN adduser You can reset your account by visiting:
npm WARN adduser
npm WARN adduser     https://npmjs.org/forgot
npm WARN adduser

You can verify you are not already using the email by going to the link https://npmjs.org/forgot and trying to have a reset email sent. When you give it all valid responses, it will respond with:

Logged in as on https://registry.npmjs.org/.

Confirm you were added by going to:

https://www.npmjs.com/~<your username>

If you already have an npm user, you can login using:

npm login

Publish the Module

Now, it’s time to publish. As long as you’re in the root of the project (with the package.json), you don’t need to specify the folder to point to that file. Include the tarball and, unless you’re a paying member, don’t forget to make the package public (it defaults to private).

npm publish file-handler-1.0.0.tgz --access public

If your project name is already taken on npm, which this example assumes, you will receive an obtuse error message that includes:

npm ERR! you do not have permission to publish "file-handler". Are you logged in as the correct user? : file-handler

To overcome the error without simply choosing a different package name, create and install a scoped package, which I discuss below. I think this is a better way to go since all of your packages will be bundled under your npm user name in the file hierarchy.
If you wish, you can search to try to find a unique name using:

npm search

To add scope, prefix your package.json "name" with @ followed by your npm user name. The @ is important and will be included in the import paths.

{
  "name": "@<your npm user name>/file-handler"
}

Create a new tarball. It will include the prefix.

npm pack

generates the file

<your npm user name>-file-handler-1.0.0.tgz

When you install the new tarball in your test project, you will find this folder structure in ./node_modules/:

/@<your npm user name>/file-handler/

Of course, you will then need to change your test project code paths to reflect the change. Don’t forget the @.

import FileHandler from '@<your npm user name>/file-handler';

Run your tests. They should just pass.

This time, publishing should work:

npm publish <your npm user name>-file-handler-1.0.0.tgz --access public

A successful publish will result in something like this:

+ @<your npm user name>/file-handler@1.0.0

Once you publish a package with a given name and version, it can never be used again. You will need to change the version in package.json.

Now, go back to your test project’s ./node_modules/ and delete

./@<your npm user name>/file-handler/

Then, to install your package from npm, run:

npm install @<your npm user name>/file-handler --save-dev

It should succeed. The output looks like this:

testFileLib@1.0.0 /Users/<your>/<src>/testFileLib
└── @<your npm user name>/file-handler@1.0.0

npm WARN testFileLib@1.0.0 No repository field.

If you check your package.json, you should find this line added to the devDependencies:

"@<your npm user name>/file-handler": "^1.0.0",

Run your tests. All should be well in the universe.

In Conclusion

Wow. This took a lot of research. In my next blog post, I will cover making updates to the npm package. The file-handler code is in my GitHub file-handler repository.

Copyright ©2014-17 Ramona Ridgewell. All rights reserved.

Posted in #Education, #npm, AmWriting, Coding, GitHub, JavaScript, Programming, Science, STEM | Tagged , , , , , , , , , , , , , , | 1 Comment

Mocha as a JavaScript Test Framework

The last few projects I discussed were to get you started coding in ES6 JavaScript. I intentionally kept the functionality very limited. In this article, I will show how to set up a test framework using my ES6 CLI Promises repository, promises. There are many different frameworks to choose from. A simple one to set up is Mocha.

Setting up

First, clone promises (the instructions for cloning are included in the article that goes with this repository, My JS Journey: Promises).

Next, install the node dependencies.

npm install

Then, build and run it to ensure everything is set up correctly.

npm run build
npm start

It should say,
hello world

Install Mocha

Install Mocha.

npm install mocha --save-dev

This should have added mocha to the devDependencies in package.json. Now is a good time to change the name.

{
  "name": "MochaExample",
  "version": "1.0.0",
  "description": "Simple Mocha example",
  "main": "index.js",
  "scripts": {
    "build": "babel src -d dist",
    "start": "node dist/index",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.24.0",
    "babel-core": "^6.24.0",
    "babel-preset-env": "^1.3.2",
    "babel-register": "^6.24.0",
    "mocha": "^3.3.0"
  }
}

Might as well check in the code.

Convert src/hello.js to Implement a class

To facilitate exporting, I find it easiest to use classes. Modify src/hello.js as follows.

class Hello {
  static getWorld() {
    return new Promise((resolve) => {
      setTimeout(() => resolve(' world'), 500);
    });
  }

  static hello() {
    return new Promise((resolve) => {
      this.getWorld().then(result => {
        resolve('hello' + result);
      });
    });
  }
}
export default Hello;

Notice that the functions changed from const to static. Also, now that they are part of the object, to reference them within the object, it is necessary to prefix them with this., e.g. this.getWorld(), as in line 10.
Modify src/index.js to accommodate the new class.

import Hello from './hello';

const sayHello = (message) => {
  console.log(message);
};

const main = () => {
    var args = process.argv;
    if (args[2] && args[2] === '--v' ) {
        console.log('Es6CliSkeleton - version 1.0.0');
    } else {
        Hello.hello().then(res => sayHello(res));
    }
};

main();

The lines that changed are 1 and 12, both of which reference the new Hello class.

Build and run to ensure everything still works.

Adding Tests

First, create a folder test. Add a file to this folder called hello_test.js.
Add the first test.

import assert from 'assert';
import Hello from '../src/hello';

describe('Hello', function() {
  describe('getWorld', function() {
    it('should return space world', function() {
      Hello.getWorld()
      .then(result => {
        assert.equal(' world', result);
      });
    });
  });
});

Next, in package.json, modify the “scripts” section’s “test” to:

"test": "mocha --compilers js:babel-core/register test/test.js"

Build and run the test.

npm run build
npm run test

You should get output something like this.

> MochaExample@1.0.0 test /Users/your_src/promises
> mocha --compilers js:babel-core/register test/*_test.js
  Hello
    getWorld
      ✓ should return space world
  1 passing (100ms)

With a nice green checkmark.
Check the code in.

A Second Test

We should have a test on the other function, Hello.hello(). It will be very similar the first one. Add this right code after the other test.

  describe('hello', function() {
    it('should return hello world', function() {
      Hello.hello()
      .then(result => {
        assert.equal('hello world', result);
      });
    });
  });

Build and run. The output should look like this.

  Hello
    getWorld
      ✓ should return space world
    hello
      ✓ should return hello world

  2 passing (65ms)

Go ahead and check that in since the next section covers something a little different.

A Broken Promise

Let’s see what happens when the promise is broken. Modify what the promise returns in Hello.getWorld() from

  setTimeout(() => resolve(' world'), 500);

to

  let input = "myErr";
  if (input === "myErr") { reject(new Error(input)); }
  setTimeout(() => resolve(' world'), 500);

Build and run the app.

> MochaExample@1.0.0 start /Users/your_src/Closet/promises
> node dist/index

(node:61097) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): 42

It fails, kind of how you might expect. Run the tests.

  Hello
    getWorld
      ✓ should return space world
(node:61087) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: myErr
    hello
      ✓ should return hello world
(node:61087) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): Error: myErr

  2 passing (111ms)

Interestingly, the tests pass, although they report the unhandled promise rejection. Let’s fix that first. Modify the tests to include a catch, which will also require the use of done in lines 6, 10 and 14, and 19, 23 and 27.

import assert from 'assert';
import Hello from '../src/hello';

describe('Hello', function() {
  describe('getWorld', function() {
    it('should return space world', function(done) {
      Hello.getWorld()
      .then(result => {
        assert.equal(' world', result);
        done();
      })
      .catch(err => {
        console.log(err);
        done(err);
      });
    });
  });
  describe('hello', function() {
    it('should return hello world', function(done) {
      Hello.hello()
      .then(result => {
        assert.equal('hello world', result);
        done();
      })
      .catch(err => {
        console.log(err);
        done(err);
      });
    });
  });
});

Now, the tests fail and let you know why:

  1) Hello getWorld should return space world:
     Error: myErr
      at src/hello.js:5:39
      at Function.getWorld (src/hello.js:3:12)
      at Context.<anonymous> (test/hello_test.js:7:13)

  2) Hello hello should return hello world:
     Error: myErr
      at src/hello.js:5:39
      at Function.getWorld (src/hello.js:3:12)
      at src/hello.js:12:12
      at Function.hello (src/hello.js:11:12)
      at Context.<anonymous> (test/hello_test.js:20:13)

Remove the changes to getWorld(). Check in the code.

In Conclusion

I generally start by writing my tests (Test Driven Development or TDD). I believe it is one of the fundamental practices in good code development. It is important to ensure you have complete test coverage. In this example, you can see I had tests for the “happy path” but had not covered potential failures. It was a bit contrived, but be on the lookout for things that can go wrong. In My JS Journey: Creating an npm Package, I show how to wrap Node fs, which is their file system interface. That blog post includes more about how to use Mocha in a less-contrived project. As that project progresses, it will have a lot of good examples where you need to test for things that might go wrong—a missing file, an empty file, invalid permissions—lots of things to test for. It also has

You can find the code for this project in my github repository, mocha-example.

Copyright ©2014-17 Ramona Ridgewell. All rights reserved.

Posted in #Education, AmWriting, Education, GitHub, JavaScript, Programming, Science, Software Development, STEM | Tagged , , , , , , , , , , | 1 Comment

Take Your Daughter to Work Day

What do you think when you hear, “Black Lives Matter?” Do you immediately think, “well, all lives matter?” If so, you’re missing the concept of systemic discrimination. It’s built into our societal norms. It won’t change unless we take steps to make it change. That might mean that someone in the group of discriminators will feel left out or cheated out of an opportunity he thinks he deserves as much as the next person. I’ll tell you this, until Black lives do matter, no lives matter in our country.

The reason I brought up the Black Lives Matter movement is to draw a comparison to another movement from the ’90s, “Take Your Daughter to Work Day.” It was an attempt by women in my industry, computer engineering, to show girls how cool coding could be—and to encourage them to study maths and sciences so that becoming a computer geek was not beyond their reaches.

Over the next couple of years, the movement spread to other disciplines—but it was about daughters. It didn’t take long for parents of boys to complain it was unfair to set aside a special day for girls. Their sons were being left out. They had never witnessed a group of children entering a computer lab—in those days, there would have been just a few machines available—the rush forward, the elbowing to get on the limited resources. Let me! Let me, do it! If they had been there, they would have seen the boys take over all of the machines, with clusters of their peers around them. The girls—at least most of them—would be standing behind the boys, watching, not doing. This was the reason to give girls a special day—to let them engage with the technology on their own terms.

Every year on Take Your Child to Work Day, I am reminded of the way girls continue to be excluded from the sciences, especially Computer Science. Back in the ’80s—the heyday of women in computing—the percentage of young women graduating in the field was around 35%. By 2013, the number had dropped to 18%. We are responsible for this drop. We encourage the practices that preclude girls from a science-rich education. For the men who rule this lucrative, high-paying profession, this leaves little competition from a whole gender—half the population—of people. I wonder if things would be better for women today if we had focused, as a nation, on educating girls in what is now called STEM.

I know, from personal experience, the challenges of being a woman in a man’s field—I  remember only being mentored by one of my male managers, and not very proactively; I was passed over for the coolest and most important projects; I was excluded from being part of “the club”—perhaps not overtly, but just by virtue of the extracurricular activities “the club” pursued, like telling an off-color joke, or going out to drink scotch and smoke cigars, or going on a camping trip to shoot guns and ride dirt bikes. In my day-to-day jobs, I have almost always been the sole woman on my team, in a hierarchy of all-men teams. All of these things, combined, leads to women in computing making only 87% of what their male counterparts are paid. The percentage of women computer engineers, from my direct observation over many years, is around 10%. When high-tech companies state their percentages at closer to twenty, they are including women who work in all capacities, such as program managers, scrum masters, human resources and recruiting—the latter two being predominantly women.

The practice of exclusion of women reaches beyond computer engineering to other high-paying professions. A good example is the Hollywood movie industry. I wrote about this a couple of years ago. It includes the fact that women directed only 6% of the top 250 U.S. grossing films in 2013. The pay gap for women is also well documented. A big deal was made of Anna Boden being selected to direct the new Marvel movie, “Captain Marvel,” although, the co-director is a man, Ryan Fleck. One of the reasons for the hoopla is that Marvel has never had a woman at the helm of one of its movies before. Maybe things are progressing at Marvel—the writers, Nicole Perlman and Meg LeFauvre, are also women, as is the star, Captain Marvel herself, Brie Larson. I hope the company hired these women on the merits of their work and not to save 30% on their wages.

So, on this Take Your Child to Work Day, remember its original intent. Also, when you think about Black Lives Matter, remember, in my field, Black Americans of all genders make up just over 5% of the employees, and Black engineers make up only 1-3%. I can count on one hand the number of Blacks I have worked with, and almost never on my own team. I have nothing against Chinese and Indian immigrants coming to America—some of my best friends are Indians, and we are all, except for Indigenous people, children of immigrants—but, in computing, they are grossly over-represented, especially in the engineering jobs. Maybe we should think about enabling our own children—most importantly women and minorities—to fill these high-paying jobs.

Don’t forget to take your daughter to work today.

Thanks to:
fortune.com
www.aauw.org
time.com/money
www.polygon.com
cra.org

Copyright ©2014-17 Ramona Ridgewell. All rights reserved.

Posted in #Education, Black Lives Matter, Coding, Education, family, Programming, Science, STEM, Uncategorized, Women | Tagged , , , , , , , , , , , , | Leave a comment

An Accessible and Usable GitHub Repository

After adding a few repositories to GitHub, I realized I neglected to discuss README.md. This is a place where you can put notes about your project which will appear on the repository page. For example, here’s the README.md from my newest repository, promises-browser.

See [this article](https://ramonaridgewell.wordpress.com/2017/04/24/my-js-journey-a-promise-in-a-browser/) for a description of how to set up this project.

It shows up at the bottom of the GitHub page, after the list of files. It’s also a good practice to add a description, a link to a webpage, and topics (up near the top).

Screen Shot 2017-04-24 at 12.06.05

I’ve been linking to the articles in my blog for setup instructions, but you could include pertinent notes in the README.md, and they will show up there.

Copyright ©2014-17 Ramona Ridgewell. All rights reserved.

Posted in #Education, AmWriting, Coding, Education, GitHub, JavaScript, Science, Women, Writing | Tagged , , , , , , , , , | Leave a comment

My JS Journey: A Promise in a Browser

In this example, I’m going to explain how to fork a GitHub repository—or copy someone else’s—as well as implement a simple promises app. As an added bonus, I threw in using a Class. The code to fork is my JavaScript browser skeleton.

Forking a Repository

In GitHub:

In the upper right, Click the Fork.

In iTerm:

Once you have your local GitHub repository, you can follow the instructions for cloning I outlined in Promises. For more on forking, see this GitHub article.

To install all the node packages, run:

npm install

Then build:

npm run build

To see it run, open index.html. When you click the Get Message button, the Message should dislpay “Hello.”

Screen Shot 2017-04-03 at 09.37.37

Adding A Class

Because I like classes, I implemented one, so you can see how that works with respect to export.

First, implement the class by changing src/hello.js as follows:

class Hello {
  static hello(){
    return 'Hello';
  }
}

export default Hello;

Modify src/index.js to import the class:

import Hello from './hello.js';

var sayHello = function () {
  return Hello.hello();
}

document.getElementById('msgBtn').addEventListener('click', function () {
    var message = sayHello();
    document.getElementById("message").innerHTML = message;
});

Build the project.

npm run build

Load or refresh index.html:
Screen Shot 2017-04-03 at 09.37.37
Checkin the code.

Adding Promises

This example is basically the same as the CLI one I described in Promises. The major difference, of course, is this one is in the browser. Promises let you ensure the order of asynchronous events, such as file reading. In my example, I retrieve the text ” world” after a timeout, and append it to “Hello” from the origin example. It’s contrived, but it shows how a promise works.

Modify src/hello.js as follows:

class Hello {
  static getWorld() {
    return new Promise((resolve) => {
      setTimeout(() => resolve(' world'), 500);
    });
  }

  static hello(){
    return new Promise((resolve) => {
      this.getWorld().then(result => {
        resolve('Hello' + result);
      });
    });
  }
}

export default Hello;

Modify src/index.js to resolve the promise returned from Hello.hello():

import Hello from './hello.js';

const sayHello = (message) => {
document.getElementById("message").innerHTML = message;
};

document.getElementById('msgBtn').addEventListener('click', () => {
Hello.hello()
.then(res => sayHello(res));
});

Build the code and refresh index.html. It should now display “Hello world” instead of simply “Hello.” You might be able to see the half-second lag on getting the message. That’s the timeout.

Screen Shot 2017-04-21 at 12.59.10

Check the code in.

In Conclusion

Promises in ES6 are not difficult, although they can be cumbersome if there are a lot of nested Promises. The new—and, as of yet, not completely supported—ES7 feature, async/await, is meant to simplify nested Promises. I’ll write about that in a future post. You can find the Browser Promise code in my github repository, promises-browser.

Copyright ©2014-17 Ramona Ridgewell. All rights reserved.

Posted in #Education, AmWriting, Coding, Education, JavaScript, Programming, Science, Women, Writing | Tagged , , , , , , , , | 1 Comment

Seattle React.js April Meetup

I had the pleasure tonight to attend the Seattle React.js April Meetup. It was hosted by Textio, who have created an augmented writing platform for creating highly effective job listings and who provided a light dinner; and Galvanize, who provide a dynamic learning community for technology and who also provide space for the event.

Host Lee Ngo, from Galvanize, started the evening by introducing Stephan Prockow, the Seattle React.js Meetup organizer. After the greetings and salutations were complete, he introduced the first guest speaker, Max Winderbaum of Textio.

Winderbaum talked about how to create lovely rich-text editors using draft-js, a JavaScript rich text editor framework, built for React and backed by an immutable model. Textio began their text editor by trying to utilize the HTML tag < contenteditable> to highlight or do other rich text enhancements. After starting down the path of writing their own solution, they found Facebook was already providing something very close to what they were trying to accomplish. State becomes immutable and atomic. It renders to all browsers the same way. And, best of all, the state is separate from the view, which facilitates testing. draft-js nicely supports plugins like draft-js-plugins. Winderbaum warned us to keep an eye out for new kid, slatejs.org. There’s always something new on the horizon for JavaScript.

The second presentation was about using react-apollo with graphql. Presenter Greg Hardin, of IceBrg.io, offered as an example a lookup from a collection of books. He covered the details of how react-apollo is integrated into the code and also cited some tools that can help with setup, such as Scaphold. Hardin explained some benefits of react-apollo with less boilerplate, the ability to run multiple named queries in the same space, mutations that an be separated from queries, and the fact that it is already integrated with redux.

mobx is another alternative to working in react. High Seas Consulting‘s Bryan Brophy gave a compelling talk on the ease of use of mobx, whose goal is simple, scalable state management. In an entertaining demo that used the Beatles as an example for band members changing state over time, Brophy showed the basic usage of mobx, including injecting stores, actions, and observers to keep the state up-to-date. It is certainly something I will look at seriously before making my next major software updates.

I’m happy I was able to be present for this well-attended event. The speakers were well-versed in their respective technologies and I learned a lot. Thanks so much to the hosts, Galvanize and Textio, and the event organizers at Seattle React.js Meetup. When video of the talks is available, I’ll add a link to it here.

Copyright ©2014-17 Ramona Ridgewell. All rights reserved.

Posted in #Education, Coding, JavaScript, Programming, Science | Tagged , , , , , , | Leave a comment

Norwescon 2017

Over the weekend, I attended Norwescon 40: Over the Hills and Far Away. It was my first time attending. I had a great time in the writing panels and workshops. You can read more about it on my writing blog.

I spent all of April 14 in writer’s panels and workshops at Norwescon 40. It was intense and exhausting, but time well-spent.

via NorWesCon 40: Over the Hills and Far Away — thewolfdreambooks

Posted in #Education, AmWriting, AmWritingFantasy, Books, Education, Fantasy, Horror, Novel, Reading, Writing | Tagged , , , , , , , , | Leave a comment