📜 ⬆️ ⬇️

webpack: 7 troubles - one answer

After my recent performance on MoscowJS # 17 with the same report , many people became interested in this instrument. Within the framework of the 11th edition of RadioJS, bashmish Misha Bashkirov told that he decided to try it in his new project, about his successful experience and a lot of positive emotions. But questions were voiced and a discussion arose, as a result of which I decided to write this article in order to reveal the main points of the report and to tell about what I did not have time.
The article is aimed at both professionals and those who have not yet encountered similar technologies.
So, let's begin.

7 troubles


The modern world of web development offers us both incredible opportunities and problems. On the scale they can be divided into two:


Global problems


  1. Decoupling decisions . HTML5 and JavaScript finally untied our hands. New and revolutionary solutions are created almost every day. Each has its own specifics, advantages and disadvantages. Moreover, they are all designed to solve a small, in fact, a range of tasks:

    • jQuery, Knockout, Angular, Marionette, React - if you push off from the details, everything is created to solve the same problems.
    • Underscore, lodash, Lazy, ES6 - in many ways, for working with data.
    • MVC, MVVM, Flux - even architectural patterns are created to solve one task.
      ')
  2. The variety of versions of these solutions increases the scale of the voiced problem by an order of magnitude:

    • One plugin requires jQuery 1.8, the second - jQuery 2.1. What to do?
    • Angular 1.3 and Angular 2 are almost completely different.
    • Bootstrap 2.3 and Bootstrap 3.1 - components created for one version will not stand out from the box for another.

  3. Pre-processing formats (containers here), for example:

    • LESS, SCSS, SASS, Stylus - for styles.
    • Handlebars, jade, EJS - for templates.
    • JSON, JSON5, PJSON, XML - for data.
    • CoffeeScript, JSX, ES6 - scripts, etc.

How is this reflected in real work?

Local problems


  1. The complexity of the growth of the project:
    • Functional - create a prototype, add a section, make a form, link the sections together, etc.
    • Technological - go to Bootstrap, connect Leaflet, implement React, etc.
  2. Dependency Management. When at least 3 scripts appear in a project, juggling starts - you constantly have to think:
    • Are the libraries loaded?
    • And the necessary styles?
    • And the templates?
    • If it's a jQuery plugin, is jQuery loaded for it?
    • And the necessary styles?
    • And the templates?
    • What other libraries do he need?
  3. Versioning (the problem is described above).

What solution?


The most optimal solution is to break the code into isolated modules. Historically, for this there were two approaches - AMD and CommonJS. A lot has been written and talked about them, but I’ll give a brief overview (if you are familiar, you may miss it).

AMD (Asynchronous Module Definition)

It is reduced to the definition of a module through define () and a call through require ():

define(['jquery', 'products'], function ($, products) { return { show: function () { products.forEach(function (item) { $('.items').append(item.html); }); } }; }); 

Conveniently enough. But with the growth of dependencies, this turns into a spaghetti code. Therefore, the developers have added a CommonJS wrapper:

 define(function (require, module, exports) { var $ = require('jquery'); var products = require('products'); module.exports = { show: function () { products.forEach(function (item) { $('.items').append(item.html); }); } }; }); 

More on this is well set out in the article from Vitaly Chirkov clslrns .

Commonjs

Natively implemented on server-side JavaScript in Node.js / Rhino.
It comes down to defining a module through a global variable and calling it via require ():

 var $ = require('jquery'); var products = require('products'); module.exports = { show: function () { products.forEach(function (item) { $('.items').append(item.html); }); } }; 

The main advantages over AMD:

Anton Shuvalov from Rambler told about this in more detail.

Both of these approaches allow:


So now what? What will bring our fantasies to life? What is the best we have today?

Meet - webpack


Just imagine. Any logic. Any formats. Your project is quickly going. Your project loads quickly. You have the most advanced development tools. And now let's take a closer look.

Quick start


For the experiment, create a directory src and in it a simple script index.js:

 console.log('Hello Habrahabr!'); 

Let's agree that in the assets directory there will be our output files (scripts, styles, images used by them). These are the files that we can upload to our web server, CDN, etc.

Globally there are two strategies for using webpack:


In both cases, we need Node.js and npm . If you have not done it before - it's time to install them now.

Console usage

To do this, we need to install the webpack globally:
 npm install webpack -g 

After that, the assembly is carried out by a simple command:
 webpack src/index.js assets/bundle.js 

Use as a module

This is the most suitable strategy for medium and large projects.
In the project directory create package.json. This can be done with the command:

 npm init 

Add a webpack module to the project:

 npm install webpack --save-dev 

To build a project, create a Node.js script. For example, build.js:

 var path = require('path'); var webpack = require('webpack'); var config = { context: path.join(__dirname, 'src'), //   entry: './index', //   ,   -  hash (entry name => filename) output: { path: path.join(__dirname, 'assets') //   } }; var compiler = webpack(config); compiler.run(function (err, stats) { console.log(stats.toJson()); //  ,    }); 

Run the build:

 node build 


Result

In both cases we get the assets directory and in it bundle.js is our compiled file, which contains index.js itself and all dependencies that it includes. In the example above, it was 1528 bytes in size.
To use it, we do not need any additional bootloader, therefore, it is enough to connect only this file:

 <!doctype html> <html> <body> <script src="assets/bundle.js"></script> </body> </html> 

That's all it worked. Fully webpack can open up only through the configuration, so I will not give examples for the console, however, you can easily discover all the magic of the console in the documentation .

Plugins


One of the main webpack extension points is plugins. They allow you to change 'on the fly' the logic of the assembly, the algorithm for finding modules, in other words, get into the heart of the assembly process.
Connection occurs through the addition of the plugins section in the transmitted settings.

Examples of plugins:


Loaders


Thanks to this expansion point, webpack provides a transparent connection to any statics - CSS, LESS, SASS, Stylus, CoffeeScript, JSX, JSON, fonts, graphics, templates, etc. You simply specify the file name in require (), and the loaders themselves provide all the necessary operations to connect it.

Connecting CSS? The loaders take care of everything themselves - they load the CSS data, and at the time of execution they add an element with these styles to the DOM.

Do you write modules in LESS, CoffeeScript or JSX? The loaders themselves will do all the pre-processing during the build - you just need to specify the file name.

Example of using loaders

Installation:

 npm install style-loader css-loader json-loader handlebars-loader url-loader --save-dev 

Setup (build.js):

 ... module: { loaders: [ {test: /\.css$/, loader: 'style-loader!css-loader'}, {test: /\.json$/, loader: 'json-loader'}, {test: /\.hbs$/, loader: 'handlebars-loader'}, { test: /\.(eot|woff|ttf|svg|png|jpg)$/, loader: 'url-loader?limit=30000&name=[name]-[hash].[ext]' }, ... 

Loaders are listed in order from right to left, i.e. for CSS, the css-loader is used first, and its result is passed to the style-loader, which places the loaded data as a <style /> block.

url-loader is a special bootloader. In this example, if the graphics and font files are up to 30kb in size, it inserts them in the form data: uri. If they exceed this volume, then it saves them to the output directory with the specified name pattern, where hash is a unique value for the file. This approach allows, on the one hand, to avoid additional calls to the server (even with Keep-Alive, this is an expensive operation), on the other, to avoid problems with caching files of the same name (this approach is known as static freeze).

Using:


Integration with React JSX

webpack is great friends with React and later it will be clear why, for now just give an example of connecting JSX scripts.

Installation:

 npm install react jsx-loader --save-dev 

Setup (build.js):

 ... resolve: { extensions: ['', '.js', '.jsx'], }, module: { loaders: [ {test: /\.jsx$/, loader: 'jsx-loader'}, ... 

Using:


Webpack-dev-server tool


Allows you to see updates on the page without rebuilding the project. Easy, convenient and fast.
How it works:

  1. Creates a web server based on your assets directory;
  2. when loading the assembly file, a connection is established via socket.io;
  3. As soon as you have changed something, the opened page is automatically updated.

Run through the console

 npm install webpack-dev-server -g webpack-dev-server --content-base assets/ 

Run via script

Installation:

 npm install webpack-dev-server --save-dev 

Using:

  1. We make the configuration in webpack.config.js, leaving only:
     var webpack = require('webpack'); var config = require('./webpack.config'); var compiler = webpack(config); compiler.run(function () { // stay silent }); 

  2. Create dev-server.js:

     var webpack = require('webpack'); var WebpackDevServer = require('webpack-dev-server'); var config = require('./webpack.config.js'); var devServer = new WebpackDevServer( webpack(config), { contentBase: __dirname, publicPath: '/assets/' } ).listen(8088, 'localhost'); 

  3. Run:

     node dev-server 

  4. Open: http: // localhost: 8088 / webpack-dev-server /

    In front of us will appear index.html with the status bar in the header: “App ready”. If we change something in the code now, the page will automatically refresh with the changes.

Hot Module Replacement - pure magic


Allows you to update, delete and add modules in real mode, i.e. even without reloading the page (thereby preserving its state). Not only is it incredibly fun, it allows you to prototype web applications an order of magnitude faster and develop complex Single Page Applications.

The author’s detailed answer to the question What is the Hot Module Replacement in Webpack?

How it works in conjunction with React:

  1. You open on one monitor - IDE, on the second - the browser.
  2. In the IDE window, change the code of your React-component, save.
  3. At this time, information about only the changed part is transmitted to the page through an open socket-connection.
  4. There is a hot-swappable component (unmount + mount).
  5. The screen automatically updates the modified component.

More information about this can be found on the developer page of the extension .
Or look at this video:



Incredible, right?

Chunks


webpack allows you to break the collected code into parts. For example, you can select common code for all pages in assets / common.js, and for each individual page make your own assets / feed.js, assets / products.js, etc. Thus, at the first load, common.js will be cached, and for each of your project pages it will be enough to load a small file with the chunk needed for it. This will significantly speed up page loading.
Looking ahead, Facebook uses about 50 chunks per page, while Instagram has an average of two, for example, common.js and Feed.js.

Performance and Analysis


According to my personal observations and the observations of colleagues, the assembly performance of the webpack is much higher than analogs. Largely due to the use of "smart" assembly and AST-parsing.

For a more subtle and more efficient optimization webpack offers advanced statistics on the result of the assembly of your project and tools for visual analysis .

Let's sum up


So, we considered:


Migration from old collectors


In addition to CommonJS, AMD is also supported out of the box - this allows you to quickly and painlessly move with Require.js.
Migrating with Browserify is as easy and magical as anything else - there is even a webpack section for Browserify users in the documentation.

How about support?


From personal experience - questions in github were answered during the day. Developers are very open and active. Did pull-request'y - the author accepted them the next day. The dynamics of commits on github is impressive .

So you can be trusted?


Of course. For example, the Facebook team uses webpack for the Instagram web interface. To be honest, while doing reverse-engineering of this project, I came across a webpack.

In addition, Twitter uses the webpack for its projects, as Nicholas Gallagher told at the Fronteers 2014 conference.

Summary


  1. The modern world of web development offers us both incredible opportunities and problems.
  2. The main problem is constant evolution (growth in the quantity and quality of both solutions and projects).
  3. This sets us the task of being flexible, open, fast and efficient.
  4. Isolated modules and a single interface of their interaction is something without which development is impossible and what makes JavaScript a full-fledged ecosystem.
  5. CommonJS has become the de facto standard in organizing modules (npm, Bower).
  6. Today, webpack is the most powerful platform for assembly and optimization, which takes into account all the experience of the previous generation of collectors (Require.js, Browserify) and implements it in the most efficient way. A webpack can easily work with taskers like Grunt and gulp, and in many cases replace them.
  7. webpack opens up the world of npm (112,393 packages) and bower (20,694 packages), making them as simple and transparent as using their modules.

I urge all of us to keep abreast. Think globally. Always evolve and see what is happening in the world. Be bold, more active, experiment. Learn how successful projects work. Do not keep to yourself, but share and share your discoveries, results and decisions. This will make each of us faster, smarter and more efficient.
Thank you for attention.

Links


Documentation for webpack - http://webpack.imtqy.com/docs/
Download and try - https://github.com/webpack/webpack
Example from the article - https://github.com/DenisIzmaylov/hh-webpack

Source: https://habr.com/ru/post/245991/


All Articles