Category: Web Development


How to package your React Component for distribution via NPM

I wrote a React component, transpiling using Babel, bundling and building using Webpack. I wanted to use it in another application via NPM. My NPM publish package needed to include component behavior, styles and images. So how difficult is it to package my React Component for distribution via NPM? An hour or so of work maybe right?

Well, it took me a lot longer to figure this out because of the following speed-bumps.
– React version conflict
– How to bundle and consume styles from a component
– How to include and bundle images

Here are the steps.

1. Make a package npm publishable

npm init

In the package.json, make sure these fields are populated:

package.json
{
    "name": "myUnflappableComponent",
    "version": "0.0.29",
    "main": "dist/index.js",
    "publishConfig": {
       "access": "restricted"
    },
    ...
}

2. Don’t bundle React. Use the parent’s React and react-dom.

  1. In package.json, add React and react-dom in the project’s peerDependencies (And remove it from dependencies, but add it to devDependencies for development)
    {
     ...
     "peerDependencies": {
         "react": ">=15.0.1",
         "react-dom": ">=15.0.1"
     },
     "devDependencies": {
         "react": ">=15.0.1",
         "react-dom": ">=15.0.1"
     },
     ...
    }
    
  2. In your webpack configuration, create a UMD bundle
     ...
     module.exports = {
     ...
     output: {
         path: path.join(__dirname, './dist'),
         filename: 'myUnflappableComponent.js',
         library: libraryName,
         libraryTarget: 'umd',
         publicPath: '/dist/',
         umdNamedDefine: true
     },
     plugins: {...},
     module: {...},
     resolve: {...},
     externals: {...}
    }
    

    And super-duper important, don’t bundle React

     module.exports = {
     output: {...},
     plugins: {...},
     module: {...},
     resolve: {
         alias: {
             'react': path.resolve(__dirname, './node_modules/react') ,
             'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
         }
     },
     externals: {
         // Don't bundle react or react-dom
         react: {
             commonjs: "react",
             commonjs2: "react",
             amd: "React",
             root: "React"
         },
         "react-dom": {
             commonjs: "react-dom",
             commonjs2: "react-dom",
             amd: "ReactDOM",
             root: "ReactDOM"
         }
     }
    }
    

3. Set up your .npmignore file

If you don’t set up a .npmignore file, npm uses your .gitignore file and bad things will happen. An empty .npmignore file is allowed. This is what mine looks like:

    webpack.local.config.js
    webpack.production.config.js
    .eslintrc
    .gitignore

4. Add a ‘prepublish’ script to your package.json

To build before publishing.

"scripts": {
     "prepublish": "rm -rf ./dist && npm run build",
    ...
}

5. Extract out your CSS files for use

We use SCSS files for our styles. These are compiled into css and extracted out by Webpack.

Install the following:

npm install --save-dev extract-text-webpack-plugin node-sass style-loader css-loader sass-loader

Update your webpack.config

const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    ...
    plugins:[
        new ExtractTextPlugin({
            filename: 'myUnflappableComponent.css',
        }),
    ],
    module:{
        rules:[
            {
                test: /\.*css$/,
                use : ExtractTextPlugin.extract({
                    fallback : 'style-loader',
                    use : [
                        'css-loader',
                        'sass-loader'
                    ]
                })
            },
            ....
        ]
    }
}

6. Images in CSS

The way you include images in your component will determine if the consumer of your component will get them.

I include them in the css file using the content property. For example

.mySky{
    width: 20px;
    height: 20px;
    content: url('../assets/images/thunderSky.png');
}

7. Make sure your images are available outside your component

The issue I ran into was the relative paths of the images in the published CSS files were messed up. After a lot of searching, this article (also in the links below) helped.

Install the following:

npm install --save-dev file-loader url-loader

Update your webpack.config like this:

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options:{
                            fallback: "file-loader",
                            name: "[name][md5:hash].[ext]",
                            outputPath: 'assets/',
                            publicPath: '/assets/'
                        }
                    }
                ]
            },
            ...
            resolve: {
                alias:{
                    ...
                    'assets': path.resolve(__dirname, 'assets')
                }
            }
        ]
    }
}

Shoutouts and References:

  1. How to publish your package on npm(all about package.json)

  2. Publish Beta to NPM

  3. Exporting images via webpack (webpack.config.js)

  4. My full webpack configuration:

const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const pkg = require('./package.json');
const path = require('path');

const libraryName= pkg.name;

module.exports = {
    entry: path.join(__dirname, "./src/index.js"),
    output: {
        path: path.join(__dirname, './dist'),
        filename: 'myUnflappableComponent.js',
        library: libraryName,
        libraryTarget: 'umd',
        publicPath: '/dist/',
        umdNamedDefine: true
    },
    plugins: [
        new ExtractTextPlugin({
            filename: 'myUnflappableComponent.css',
        }),
    ],
    node: {
      net: 'empty',
      tls: 'empty',
      dns: 'empty'
    },
    module: {
        rules : [
            {
            test: /\.(png|svg|jpg|gif)$/,
            use: [
                {
                    loader: 'url-loader',
                    options:{
                        fallback: "file-loader",
                        name: "[name][md5:hash].[ext]",
                        outputPath: 'assets/',
                        publicPath: '/assets/'
                    }
                }    
            ]
        },
        {
            test: /\.*css$/,
            use : ExtractTextPlugin.extract({
                fallback : 'style-loader',
                use : [
                    'css-loader',
                    'sass-loader'
                ]
            })
        },
        {
            test: /\.(js|jsx)$/,
            use: ["babel-loader"],
            include: path.resolve(__dirname, "src"),
            exclude: /node_modules/,
        },
        {
            test: /\.(eot|ttf|woff|woff2)$/,
            use: ["file-loader"],
        },
        {
            test: /\.(pdf|doc|zip)$/,
            use: ["file-loader"],
        }]
    },
    resolve: { 
        alias: { 
            'react': path.resolve(__dirname, './node_modules/react') ,
            'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
            'assets': path.resolve(__dirname, 'assets')
        } 
    },
    externals: {
        // Don't bundle react or react-dom
        react: {
            commonjs: "react",
            commonjs2: "react",
            amd: "React",
            root: "React"
        },
        "react-dom": {
            commonjs: "react-dom",
            commonjs2: "react-dom",
            amd: "ReactDOM",
            root: "ReactDOM"
        }
    }
};

Introducing Book-Notes – my notes and highlights from the books I have read

Today I’m releasing Book-Notes – a collection of my notes and highlights from the books I have read.

Screenshot of Book-notes

Reading a book is awesome. Blazing past books at break-neck speed is awesome for only so long. To enjoy the book more, to internalize and chew over what the book has to say, I realized that slowing down and reviewing might be key. So, I started marking out highlights and taking notes when reading inspired by folks like Derek Sivers, Ryan Holiday, Maria Popova (listen at the 31:45 mark) and Tim Ferriss.

This taking notes and highlights is convenient and easy when reading an e-book: on a kindle or the kindle app, or on the Google Play Books app. If I’m reading a paper book, I use the index method: I lightly mark the start and end of the highlight on the page and create an index on the very first page of the book. The index is just a list of page numbers which has these highlights and maybe notes.

I download the Kindle highlights from the Kindle – Your Highlights page using Bookcision. When reading on Play books, it stores the notes on a Google Doc in my Google Drive. Paper books are slower/harder/better/nicer/more-painful. I write down the marked highlights and erase the pencil markings as I go) into my Livescribe book – which gets transcribed and then moved to OneNote.

And now, these notes converted to JSON and will start appearing on the book-notes section of my website.

So, if you are interested in what I’m reading, what I think is thought-provoking in the books I read, come back here regularly to check for new notes and highlights (and some older ones which are being transcribed).

What I used to build book-notes

I used React – using Create React App to build book-notes. It is hosted on my shared hosting space at Webhosting Hub. The code lives in Bitbucket. The design is heavily inspired by Derek Sivers and the Kindle – Your Highlights page. Fonts used: the serif Alegreya for body copy and and the sans-serif Gandhi Sans for headers. Logo is from Flaticon.


VS Code Setup Guide 1

In the past few year, I have used Sublime Text as the text editor of my choice for Front End Web Dev work (and to draft these blog posts). I wanted to try a different text editor (FOMO, next cool thing, need more fun … whatever) and decided to try Visual Studio Code or VS Code. This post is my VS Code setup guide.

VS Code is made by the makers of OneNote (which I adore), and it has good reviews from other dev folks. It is also free and has an extensive extensions market. In addition to the installation, in this guide, I list some of the many extensions to improve productivity from the get go and to try to replicate some features I loved in Sublime Text.

Here is the set of links I followed for setup, configuration and customization.

Installation

  1. Installation Link
  2. On Mac only: setup the command prompt for command line invocation.

Customize the Look and Feel

  1. Nomo Dark icon theme: Icons in your explorer window to identify the files types / folders easily.After installing, enable the extension by going to File > Preferences > File Icon Theme > VSCode Icons. (On OSX it is Code > Preferences > File Icon Theme > VSCode Icons.)
  2. Kary Foundation Theme Light theme: I pretty much use light themes. I like the color scheme and the recommended typography. Out of the box, the fonts and text color in this theme isnt’t that great. You absolutely need need to install the recommended Hasklig font, and then it becomes really good.After installing, enable the theme by going to File > Preferences > Color Theme and select “Kary Foundation Theme – Light”
  3. Hasklig Font: A code font by Adobe Systems with monospaced ligatures, recommended for use with the Kary Foundation Theme. After installing the theme on your OS, enable the font. Then go to File > Preferences > Settings and update your settings with the following:
    {  
      "workbench.iconTheme": "vs-nomo-dark", 
      "workbench.colorTheme": "Kary Foundation - Light", 
      "editor.fontFamily": "Hasklig, Menlo, Monaco, 'Courier New', monospace",  "editor.fontWeight": "500", 
      "editor.fontWeight": "normal",
      "editor.fontSize": 15,
      "editor.fontLigatures": true,
      "terminal.integrated.fontFamily": "Hasklig, Menlo, Monaco, 'Courier New', monospace",
      "terminal.integrated.fontLigatures": true
    }  

Set up the editor conveniences

  1. Path Intellisense Visual Studio Code: Plugin that autocompletes filenames.
  2. NPM Intellisense Visual Studio Code: Plugin that autocompletes npm modules in import statements.
  3. Auto Close Tag: Automatically add HTML/XML close tag, same as Visual Studio IDE or Sublime Text does.
  4. Auto Rename Tag: Automatically rename paired HTML/XML tag, same as Visual Studio IDE does.
  5. Expand Selection To Scope: This extension introduces a command that incrementally expands the selection to the nearest outer scope (delimited by bracket pairs).
  6. Paste and Indent: Paste some code with “correct” indentation.
  7. AB HTML Formatter: This tool is formatting / reindenting HTML code.
  8. Rainbow Brackets: Provides rainbow colors for the round brackets, the square brackets and the squiggly brackets.
  9. Guides:Guides is simply an extension that add various indentation guide lines.
  10. Color Highlight: Highlight web colors in your editor.
  11. Color Picker: Helper with GUI to generate color codes such as CSS color notations.

Set up the development conveniences

  1. ES Lint: ESLint Integrates ESLint into VS Code. You need to have installed ESLint first.
    npm install eslint
    
  2. CSS Auto Prefix: Auto-prefixes certain attributes in CSS.
  3. Style Lint: Modern CSS/SCSS/Less linter.Enable the linter, while disabling the built-in CSS and SCSS linter. Go to File > Preferences > Settings and add the following to settings.json:
    { 
      "stylelint.enable": true,
      "css.validate": false, 
      "scss.validate": false 
    }
    
  4. HTML CSS Support: CSS support for HTML documents.
  5. HTML Snippets: Full HTML tags including HTML5 Snippets.
  6. HTML Boilerplate: A basic HTML5 boilerplate snippet generator.
  7. Gulp Snippets: Gulp JS Snippets for Visual Studio Code.

Projects and versioning

  1. Git Extension Pack: Popular Visual Studio Code extensions for Git. Contains the following extensions:
    1. Git History: View git log, file or line History.
    2. Project Manager: Easily switch between projects.
    3. Git Lens: Provides Git CodeLens information (most recent commit, # of authors), on-demand inline blame annotations, status bar blame
      information, file & blame history explorers, and commands to compare changes.
    4. gitignore: Language support for .gitignore files. Lets you pull .gitignore files from the https://github.com/github/gitignore repository.
    5. Open in GitHub / Bitbucket / VisualStudio.com: Jump to a source code line in Github / Bitbucket / VisualStudio.com.

Measuring (for the dataphiles)

  1. Wakatime: Metrics, insights, and time tracking automatically generated from your programming activity.

Debuggers

  1. Debugger for chrome: Debug your JavaScript code in the Chrome browser, or any other target that supports the Chrome Debugger protocol.
  2. Debugger
    for firefox
    : Debug your web application or browser extension in Firefox

Polymer Specific

These extensions are specific to Polymer – a JavaScript library that helps you create custom reusable HTML elements, and use them to build performant, maintainable
apps.

  1. Polymer IDE: Provides linting, autocompletion, and more for web components.
  2. Polymer Syntax: Polymer syntax highlighting for Atom & VS Code!
  3. Polymer Snippets: Sublime snippets for Polymer and Web Components

Additional Settings

These are additional changes to the editor settings to make life easier. Go to File > Preferences > Settings and add the following lines to your settings.json file

  1. Change tab size from 4 spaces (default) to 2 spaces.
    {
      "editor.tabSize": 2
    }
    
  2. Enable word-wrap – if you are crazy like me.
    {
      "editor.wordWrap": "on"
    }
    
  3. Enable the minimap to quickly navigate long files.
    {
      "editor.minimap.enabled": true
    }
    
  4. Show white spaces outside words
    {
      "editor.renderWhitespace": "boundary"
    }
    
  5. Enable formatting on typing and pasting.
    {
      "editor.formatOnType": true,
      "editor.formatOnPaste": true
    }
    
  6. Enable copying the current line when Ctrl+C is pressed without any selection. – Enabled by default!
  7. Enable Files Auto-Save
    {
      "files.autoSave": "afterDelay",
      "files.autoSaveDelay": 8000
    }
    
  8. Enable Polymer to analyze the whole package, though it’s slower:
    {
      "polymer-ide.analyzeWholePackage": true
    }
    

The settings.json file now looks like


// Place your settings in this file to overwrite the default settings
{
    "workbench.iconTheme": "vs-nomo-dark",
    "workbench.colorTheme": "Kary Foundation - Light",
    "editor.fontFamily": "Hasklig, Menlo, Monaco, 'Courier New', monospace",
    "editor.fontWeight": "500",
    "editor.fontSize": 15,
    "editor.fontLigatures": true,
    "terminal.integrated.fontLigatures": true,
    "editor.tabSize": 2,
    "editor.wordWrap": "on",
    "editor.minimap.enabled": true,
    "editor.renderWhitespace": "boundary",
    "editor.formatOnType": true,
    "editor.formatOnPaste": true,
    "terminal.integrated.fontFamily": "Hasklig, Menlo, Monaco, 'Courier New', monospace",
    "stylelint.enable": true,
    "css.validate": false,
    "scss.validate": false,
    "files.autoSave": "afterDelay",
    "files.autoSaveDelay": 8000,
    "polymer-ide.analyzeWholePackage": true
}


Introducing LittleReads – The most awesome book tracking app in the universe

This is a side project I’ve been working on since November 2016. Here is the grand reveal. I’ll blog technical about the making of Littlereads over the next few weeks. Meanwhile, here is the introduction.

LittleReads LogoLittleReads

The most awesome book tracking app in the universe


Superhero couple image

Do you have a child under 6?

Do you read books to your child?

Are you participating in the 1000 books before kindergarten challenge?

Do you want your child to be a super-duper-reader?

Do you want an easy way to track books you read to your child?

Yes? Join us at littlereads.us

Littlereads is modern. LittleReads works on iPhones, Android devices, desktops, laptops,
LittleReads even works offline!
(Told you … it’s awesome! Better than sliced bread even…)

My Story

I have a superpower. I go places.
kids reading imagination image

Utopias, dystopias, future time, past time, alternate time, dungeons with dragons, androids and superworms, new galaxies, universes, multiverses. All are just a book away.

I want to pass this superpower to my daughter. So I read to her.

We go to the library, hang out there, color there, read books there. And bring home a lot of books.

I even signed up for the 1000 books before 6 challenge. I tried the book provided to track read books, but wanted a more convenient digital option. And I have forgotten the books she loved (and I loved to read) when she was 1,2,3…
So I went looking in the wild, for a way to track books. I found a few – but none of them catered to the young ones… you could not track when and how many times you read the same book.

So I decided to scratch my own itch and develop a rash. I mean, an app which is simple, colorful, easy to use, which can track the books I read to her and show me that data in pretty charts. So after about 6 months of development, here is LittleReads.

So please tell me…

What do you think about LittleReads?

Can you use it and tell me what you think? Any bugs, issues? What features you would like to see? Something not working the way you like?

You can email or Tweet @suprada with feedback. Waiting eagerly to hear what you have to say.

Happy reading (and tracking),
Suprada


Share LittleReads with the world:

  • Tweet: Parents, check out #LittleReads - most awesome book tracking app in the universe for your little ones!
  • … or Just forward this email


A history of website development of sofobomo.com Part II

Note: Part I here

Part II : Setting up a development environment for sofobomo.com

The question is, as a one-person team of sofobmo.com (until 2016 – when Matt joined me … Hi Matt!), how did I set up www.sofobomo.com, and how have I managed, updated, made changes to SoFoBoMo till now? Why, by myself of course. The site is live on a webhost. Any changes I need to make, I make it directly on the site itself – the production environment, so to speak? Are you cringing, shuddering reading this? You should be….

Crazily, until I started my job as a front end engineer, I never realized the magnitude of my mistake. No development environment, no version control, none of these safeties for my baby! (Shudder…)

Back in July, when SoFoBoMo 2016 started, I vowed to myself this would change. Because Matt joined Sofobomo, and it doesn’t help a team when one person makes random changes on the website – just to try things out. And also because of the massive UI changes we need to make to the website for Sofobomo 2017 – make the site responsive, add Facebook integration, add beautiful forums, some voting scheme and other features.

So I spent some time in September, setting up a development environment on my Macbook. I had, in the past tried to use the MAMP stack, but never actually got it completely functioning – mostly because I was not as motivated. This time however, I was as highly motivated as can be, and was commited to a development environment. As of writing this, the Drupal official site seems to recommend using Virtual Box and a pre-made Vagrant setup. I decided to try this out and use Drupal-VM.

The setup was super easy – following the instructions in the quick start guide. I downloaded my production site files, downloaded the current database from the production site using the Backup and Migrate module. I then downloaded and installed Virtual Box, Vagrant and Ansible. As per the instructions, I made a copy and updated the config.yml file to point to my downloaded codebase (Drupal files) (and disabled installing a fresh Drupal instance). I also updated the config file with the downloaded database details, and enabled Adminer as one of the development dependencies. Then a “vagrant up” on the command line and waiting for everything to be installed. And finally adding the VM IP address to my hosts file and I was ready to go. Simple, easy. In fact, much easier than what I was expecting. Now, if only my shared web hosting provider would enable Drush so I can just push updates via the command line!

And so, that’s how I have a development environment for www.sofobomo.com. Pair it with version control with Git and backup the files in bitbucket or github, and I am ready to start making changes for SoFoBoMo 2017!