Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active October 3, 2018 09:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Integralist/8d2744cf001c689425568e75c3b75ffa to your computer and use it in GitHub Desktop.
Save Integralist/8d2744cf001c689425568e75c3b75ffa to your computer and use it in GitHub Desktop.
[Modern JS] #javascript #js #modern #tools #transpilers #babel #webpack

Ensure you have Node/NPM installed, then make a project directory:

mkdir modern-js && cd modern-js

Create an empty package.json file:

npm init -y

Install dependencies:

npm install --save-dev webpack \
                       webpack-cli \
                       webpack-dev-server \
                       @babel/core \
                       @babel/preset-env \
                       "babel-loader@^8.0.0-beta" \
                       style-loader \
                       css-loader \
                       sass-loader \
                       node-sass \
                       eslint@4.x babel-eslint@8

npm install --save @babel/polyfill

Note: the dev dependencies need to be installed in the order they're specified, otherwise npm will complain/fail.

Your package.json will now have the following dependencies:

{
  "name": "modern-js",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.1.2",
    "@babel/preset-env": "^7.1.0",
    "babel-eslint": "^8.2.6",
    "babel-loader": "^8.0.4",
    "css-loader": "^1.0.0",
    "eslint": "^4.19.1",
    "node-sass": "^4.9.3",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.0",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9"
  },
  "dependencies": {
    "@babel/polyfill": "^7.0.0"
  }
}
  • Babel: transpiler of modern JS into ES5 compatible code
  • Webpack: a js module bundler (but also capable of transforming, bundling, packaging just about anything).

Now create a webpack config file:

webpack.config.js

Note: babel configuration will be placed inside of the package.json file, but can also be extracted into its own .babelrc file if you prefer.

Add the following code to your webpack configuration:

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
        }
      }
    ]
  }
}

Update your package.json to include script commands for webpack:

{
  ...
  
  "scripts": {
    "build": "webpack --mode production",
    "dev": "webpack-dev-server --mode=development --config webpack.config.js",
    ...
  },
  
  "babel": {
  	"presets": [
    	["@babel/env", {"modules": false}]
    ],
    "plugins": ["syntax-dynamic-import"]
  }
  
  ...
}

The webpack package also supports watching files for changes --watch but it doesn't handle 'hot reloading' (i.e. meaning you'll need to manually refresh your service, which if you've got a complex 'single page application' will result in you losing your current state).

Note: the babel configuration prevents babel from transpiling import and export statements into ES5, and enables dynamic imports.

Now create a JavaScript file that you want to transpile and bundle:

mkdir src dist
touch .eslintrc src/index.js src/component.js dist/index.html

Here's the contents of index.js:

/*eslint no-undef: "error"*/
/*eslint-env browser*/

import '@babel/polyfill';

import c from './component.js';

console.log(c);

let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a);
console.log(b);

const root = document.createElement('div');
root.innerHTML = `<p>Hello Webpack!</p>`;
document.body.appendChild(root);

Note: instead of using eslint-env browser you could add a globals field to your .eslintrc (see below for example). You can also use eslint-env node for server-side JS. See the docs for more information.

Here's the contents of component.js:

const c = ['x', 'y', 'z'];

export default c;

Here's the contents of index.html:

<!doctype html>
<html>
  <head>
    <title>Hello Webpack</title>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

Here's the contents of .eslintrc:

{
  "parser": "babel-eslint",
  "globals": {
    "console": true,
    "document": true,
    "window": true
  },
  "rules": {
    'brace-style': [2, '1tbs', {'allowSingleLine': true}],
    'camelcase': 2,
    'comma-spacing': 2,
    'comma-style': 2,
    'curly': 2,
    'eol-last': 2,
    'indent': [2, 2],
    'key-spacing': 2,
    'new-cap': 2,
    'new-parens': 2,
    'no-lonely-if': 2,
    'no-multi-spaces': 2,
    'no-multiple-empty-lines': [2, {'max': 2}],
    'func-call-spacing': 2,
    'no-trailing-spaces': 2,
    'quotes': [2, 'single', {'allowTemplateLiterals': true}],
    'semi': 2,
    'semi-spacing': 2,
    'space-before-blocks': 2,
    'space-in-parens': 2,
    'space-infix-ops': 2,
    'space-unary-ops': 2,
    'array-callback-return': 2,
    'block-scoped-var': 2,
    'consistent-return': 2,
    'eqeqeq': 2,
    'guard-for-in': 2,
    'no-array-constructor': 2,
    'no-caller': 2,
    'no-cond-assign': 2,
    'no-const-assign': 2,
    'no-control-regex': 2,
    'no-delete-var': 2,
    'no-dupe-args': 2,
    'no-dupe-class-members': 2,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-empty-character-class': 2,
    'no-empty-pattern': 2,
    'no-eval': 2,
    'no-ex-assign': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-fallthrough': 2,
    'no-func-assign': 2,
    'no-implied-eval': 2,
    'no-invalid-regexp': 2,
    'no-iterator': 2,
    'no-lone-blocks': 2,
    'no-loop-func': 2,
    'no-mixed-operators': [2, {
      groups: [
        ['&', '|', '^', '~', '<<', '>>', '>>>'],
        ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
        ['&&', '||'],
        ['in', 'instanceof']
      ],
      allowSamePrecedence: false
    }],
    'no-multi-str': 2,
    'no-native-reassign': 2,
    'no-unneeded-ternary': 2,
    'no-unsafe-negation': 2,
    'no-new-func': 2,
    'no-new-object': 2,
    'no-new-symbol': 2,
    'no-new-wrappers': 2,
    'no-obj-calls': 2,
    'no-octal': 2,
    'no-octal-escape': 2,
    'no-redeclare': 2,
    'no-regex-spaces': 2,
    'no-script-url': 2,
    'no-self-assign': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-shadow-restricted-names': 2,
    'no-shadow': 2,
    'no-sparse-arrays': 2,
    'no-template-curly-in-string': 2,
    'no-this-before-super': 2,
    'no-throw-literal': 2,
    'no-undef': 2,
    'no-unexpected-multiline': 2,
    'no-unreachable': 2,
    'no-unused-expressions': [2, {
      'allowShortCircuit': true,
      'allowTernary': true
    }],
    'no-unused-vars': 2,
    'no-use-before-define': [2, 'nofunc'],
    'no-useless-computed-key': 2,
    'no-useless-concat': 2,
    'no-useless-constructor': 2,
    'no-useless-escape': 2,
    'no-useless-rename': 2,
    'no-with': 2,
    'radix': 2,
    'require-yield': 2,
    'use-isnan': 2,
    'valid-typeof': 2,
    'wrap-iife': [2, 'any']
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment