Skip to content

Latest commit

 

History

History
358 lines (273 loc) · 16.6 KB

File metadata and controls

358 lines (273 loc) · 16.6 KB

Webpack

Webpack 2.0 is getting real

We want to write modular code. But browsers cannot run modularised code, so we need a module bundler. UIs aren't just JavaScript though. Our UI components can also depend on images, fonts, and CSS. Webpack recognises that and with the help of loaders, supercharges the require function so you can explicitly require all of your dependencies.

Webpack uses "loaders" to preprocess files while browserify uses "transforms".

npm init -y

npm i webpack --save-dev

npm i file-loader --save-dev
npm i url-loader --save-dev

npm i css-loader --save-dev
npm i style-loader --save-dev
npm i postcss-loader --save-dev
npm i postcss-cssnext --save-dev

npm i babel-core --save-dev
npm i babel-loader --save-dev

npm i eslint --save-dev
npm i eslint-loader --save-dev
npm i babel-eslint --save-dev

npm i babel-preset-es2015 babel-preset-react --save-dev
npm i babel-preset-react-hmre --save-dev

npm i react react-dom --save

OLD

▶ npm install react --save --save-exact
▶ npm install --save normalize.css
▶ npm install --save-dev babel-loader # Will add webpack also
▶ npm install --save-dev babel-eslint
▶ npm install --save-dev eslint-loader
▶ npm install --save-dev eslint-plugin-react
▶ npm install --save-dev url-loader
▶ npm install --save-dev css-loader
▶ npm install --save-dev style-loader
▶ npm install --save-dev sass-loader
▶ npm install --save-dev postcss-loader
▶ npm install --save-dev autoprefixer-core
▶ npm install --save-dev react-hot-loader
▶ npm install --save-dev extract-text-webpack-plugin
▶ npm install --save-dev webpack-dev-server
▶ npm install --save-dev assets-webpack-plugin
▶ npm install --save camelize

The webpack core can be extended with loaders and plugins.

Starter Kit, Boilerplate

ESLint

// .eslintignore - from redux examples
**/dist/*
**/node_modules/*
**/server.js
**/webpack.config*.js

Loaders

The loaders will only kick into action when you try to require something that match the test patterns.

Loaders and plugins are commonly confused with each other, but they are completely different things.

Roughly speaking, loaders deal with each source file, one at a time, as they are "loaded" by webpack during the build process. Plugins in the other hand do not operate on individual source files: they influence the build process as a whole.

Plugins

Globals?

// See https://gist.github.com/Couto/b29676dd1ab8714a818f
plugins: [
  new webpack.ProvidePlugin({
    'Promise': 'es6-promise',
    'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
  })
]

// Or should we just use babel-polyfill?

webpack.config.js

// Here when you compile the code it will be temporarily saved into build/js folder.
// Webpack Dev Server will in turn make that folder's scripts available at the URL /public/assets/js

module.exports = {
  context: path.resolve('js').
  entry: [],
  output: {
    path: path.resolve('build/js/),
    publicPath: '/public/assets/js',
    filename: 'bundle.js'
  },
  
  devServer: {
    contentBase: 'public'
  }
};

Single entry or multiple entries for code splitting.

Webpack is mainly a JavaScript-bundler. Its "native" language is JavaScript and every other source requires a loader which transforms it to JavaScript.

Alias

// npm install backbone jquery underscore
resolve: {
  alias: {
    jquery: 'lib/jquery-3',
    underscore: 'lib/lodash'
  }
}

CSS in Webpack

You divide your modules by folders and include both CSS and JavaScript files in those folders. See entry.

In Webpack, each Sass file is complied in isolation. It means you need to @import dependencies like variables and mixins wherever you use them!?

// header.scss
@import 'config/colors'

.header { color: $red; }
// Loaders will be applied from right to left, piping?
// Use ! to chain loaders
style!css!sass?includePaths[]=
  • style-loader - take a string, create a <style> and handed to DOM
  • css-loader - returns JavaScript string, resolve @import and url
  • sass-loader
  • file-loader - for css-loader to include images assets

style-loader injects <style> tag at runtime so it should not work server-side. You can load CSS as just text and then inject it manually.

If include isn't set, Webpack will traverse all files within the base directory. This can hurt performance! It is a good idea to set up include always. There's also exclude option that may come in handy. Prefer include, however.

webpack-dev-server

Deprecated? Replaced by webpack-hot-middleware? webpack-hot-middleware allows you to add hot reloading into an existing server without webpack-dev-server.

A Node.js express server using webpack-dev-middleware to serve webpack bundle.

Hot Module Replacement (HMR)

Without hot loading, the browser essentially refreshes with a flash and loses all states.

If you have this problem:

GET http://localhost:3000/__webpack_hmr net::ERR_INCOMPLETE_CHUNKED_ENCODING

It means you cannot use nodemon to restart server and have HMR working.

If you get this error:

Uncaught (in promise) Error: Aborted because 167 is not accepted(…)

It means you are editing the root component.

Feature Flags

Production

Run uglify dead-code elimination.

webpack -p -d // source-map in production (minified also)

Especially with lodash or moment.js:

// Don't do this
import { concat, sortBy, map, sample } from 'lodash';

// Instead, require individually
import concat from 'lodash/concat';
import sortBy from 'lodash/sortBy';
import map from 'lodash/map';
import sample from 'lodash/sample';

HTML Hash Injection

Use assets-webpack-plugin to access the JSON stats object.

Code Splitting and Lazy Loading

Webpack allows you to split bundles in various ways. You can even load them dynamically as your application gets executed. This sort of lazy loading comes in handy for large applications. You can load dependencies as you need them.

const login = require('./login'); // will be bundled

login(() => {
  // hints to webpack to split this code out of the bundle
  // but "ensure" that it is available before the callback runs

  require.ensure([], () => {
    // webpack will load this dynamically when needed
    var willNotBeBundled = require('./DashboardPage');
  });
});

Webpack with Rails

Use JSON manifest file for production fingerprinting.

  1. Forget about Rails Asset Pipeline.
  2. Have a folder called "front-end", "fe" or "webpack"
  3. Use foreman to start Rails server + webpack watcher
  4. Ask webpack to build assets for us and put it directly in /public folder.
  5. Generate JSON file with the hashes fingerprinting for Rails view to use. See assets-webpack-plugin
  6. Do not commit the generated bundle from webpack! gitignore it also.

Videos