Web Bundler CheatSheet belongs to the awesome-Cheatsheet series. Welcome to join the front end team of Ali Nanjing, welcome to pay attention to the special issue of Ali Nanjing technology for more information.
Web Bundler CheatSheet | Web construction and packaging tools inventory
When we’re ready to embark on a Web-related project, the right scaffolding can make a big difference. In 2016, My Frontend Path: Instrumentalization and Engineering, we discussed instrumentalization and engineering, with an important chapter on so-called packaging tools. Grunt and Glup belong to Task Runner, that is, Task executor. In fact, scripts defined in NPM package.json can also be considered Task Runner, while Rollup, Parcel, and Webpack are Bundler, a packaging tool.
Different building tools have their own application scenarios. Webpack is a great build and packaging tool, but it provides basic and complex functionality support that doesn’t fit all scenarios. A zero-configuration packaging tool such as Parcel is great for application prototyping projects, while Rollup or Microbundle is great for library packaging, Backpack can help us quickly build node.js projects. The tools I discuss in this article are only the tools I use on a daily basis. Check out Browserify, Fusebox, and other build tools for the Web Build and packaging Tool Index or modern Web development practices/advancements.
Parcel
Parcel is a well-known zero-configuration application packaging tool that can quickly build applications in algorithm-based experiments/game scenario builds like TensorflowJS or Gh-Craft.
# installation Parcel
$ npm install -g parcel-bundler
Start the development server
$ parcel index.html
# execute online compilation
$ parcel build index.js
# specify the compile path
$ parcel build index.js -d build/output
Copy the code
Parcel automatically downloads and installs dependencies for us and has built-in ES, SCSS, and other common processors. React, React & TypeScript, Vue. Js, etc. Examples of React, React & TypeScript, Vue. Js are provided in fe-Boilerplate.
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import logo from '.. /public/logo.svg';
import './index.css';
const App = (a)= > (
<div className="App">
<img className="App-Logo" src={logo} alt="React Logo" />
<h1 className="App-Title">Hello Parcel x React</h1>
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));
// Hot Module Replacement
if (module.hot) {
module.hot.accept();
}
Copy the code
Then define the entry’s index.html file:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Parcel React Example</title>
</head>
<body>
<div id="root"></div>
<script src="./index.js"></script>
</body>
</html>
Copy the code
Then run the development server using Parcel index.html. Parcel also supports asynchronous loading, assuming we define some code in the somemodule.js file and load it when the user actually needs it:
// someModule.js
console.log('someModule.js loaded');
module.exports = {
render: function(element) {
element.innerHTML = 'You clicked a button'; }};Copy the code
Use import in an entry file for asynchronous loading:
console.log('index.js loaded');
window.onload = function() {
document.querySelector('#bt').addEventListener('click'.function(evt) {
console.log('Button Clicked');
import('./someModule').then(function(page) {
page.render(document.querySelector('.holder'));
});
});
};
Copy the code
Finally, Parcel has built-in support for WebAssembly and Rust with a simple import that uses the WASM module:
// synchronous import
import {add} from './add.wasm';
console.log(add(2.3));
// asynchronous import
const {add} = await import('./add.wasm');
console.log(add(2.3));
// synchronous import
import {add} from './add.rs';
console.log(add(2.3));
// asynchronous import
const {add} = await import('./add.rs');
console.log(add(2.3));
Copy the code
Here add.rs is a simple addition function written in Rust:
#[no_mangle]
pub fn add(a: i32, b: i32) - >i32 {
return a + b
}
Copy the code
Rollup + Microbundle
Rollup is a purer module packaging tool that is better suited to building libraries than Parcel or Webpack, React, vue.js, Angular, D3, Moment, Redux, and many other great libraries are built with Rollup. Rollup can build source code written according to ESM(ES2015 Module) specification into IIFE, AMD, CommonJS, UMD, ESM and other formats, and it supports Tree Shaking, Scope reactive optimization features earlier. Ensure the simplicity and efficiency of the module. The Rollup example configuration project we use here is stored in fe-Boilerplate/Rollup. The simplest rollup.config.js file configuration is as follows:
export default {
// Specify the module entry
entry: 'src/scripts/main.js'.// Specify the package name
dest: 'build/js/main.min.js'.// Specify the file format
format: 'iife'.// Specify the SourceMap format
sourceMap: 'inline'
};
Copy the code
If we had just packaged the simple sayHello function, the output file would have simply been wired and called, and cleared of unused modules:
(function() {
'use strict'; . function sayHelloTo(name) { ... }... const result1 = sayHelloTo('Jason'); . }) ();//# sourceMappingURL=data:application/json; charset=utf-8; base64,...
Copy the code
Rollup also has a rich plugin system. In Fe-BoilerPlate/Rollup we also introduce common aliases, ESLint, environment variable definitions, package compression and analysis, etc. Using the most common Babel and TypeScript examples, if we need to import Babel in a project, we can also configure the.babelrc file in the root directory and import rollup-plugin-babel:
import { rollup } from 'rollup';
import babel from 'rollup-plugin-babel';
rollup({
entry: 'main.js'.plugins: [
babel({
exclude: 'node_modules/**'
})
]
}).then(...)
Copy the code
For TypeScript, the rollup-plugin-typescript plugin is introduced:
import typescript from 'rollup-plugin-typescript';
export default {
entry: './main.ts'.plugins: [typescript()]
};
Copy the code
Microbundle is Developit’s Rollup based zero-configuration lightweight packaging tool that currently has built-in support for TypeScript and Flow and requires no additional configuration. I also used this tool in the packaging of the JS-SwissGear/X-FETCH project.
{
"scripts": {
"build": "microbundle"."dev": "microbundle watch"}}Copy the code
- Index.js is a CommonJS module, which is a built-in module type for Node.js and is used in a similar way to
require('MyModule')
Grammar import - Index.m.js is an ECMAScript module that uses similar functions as
import MyModule from 'my-module'
Grammar import - Index.umd. js is a UMD module
- Index. d.ts is a TypeScript type declaration file
Webpack
As a well-known packaging tool, Webpack allows us to specify the entry address of the project, and then automatically package the resources used into the package file through Loader and Plugin conversion. For example, fe-BoilerPlate/React-Webpack, Fe-Boilerplate/React-webpack-ts, Fe-Boilerplate/Vue – Webpack, etc.
Webpack also currently supports zero configuration running
$ npm install webpack webpack-cli webpack-dev-server --save-dev
Copy the code
"scripts": {
"start": "webpack-dev-server --mode development",
"build": "webpack --mode production"
},
Copy the code
Basic configuration
const config = {
// Define the entry
entry: {
app: path.join(__dirname, 'app')},// Define the package file
output: {
// Output directory
path: path.join(__dirname, 'build'),
// Output the file name
filename: '[name].js'
// Use hash as the file name
// filename: "[name].[chunkhash].js",
},
// Define how to handle
module: {
rules: [{test: /\.js$/.use: 'babel-loader'.exclude: /node_modules/}},// Add additional plug-in actions
plugins: [new webpack.DefinePlugin()]
};
Copy the code
Webpack also supports adding multiple configurations:
module.exports = [{
entry: './app.js'.output:... . }, {entry: './app.js'.output:... . }]Copy the code
The resolve module takes care of the require and import resolution specifications in our code, which include extensions, aliases, modules, and so on:
const config = {
resolve: {
alias: {
/ *... * /
},
extensions: [
/ *... * /].modules: [
/ *... * /]}};Copy the code
Resource to load
const config = {
module: {
rules: [{// **Conditions**
test: /\.js$/.// Match files
enforce: 'pre'.// "post" too
// **Restrictions**
include: path.join(__dirname, 'app'),
exclude: path= > path.match(/node_modules/),
// **Actions**
use: 'babel-loader'}}};Copy the code
// Process foo.png through url-loader and other matches
import 'url-loader! ./foo.png';
// Override possible higher level match completely
import '!!!!! url-loader! ./bar.png';
Copy the code
Babel-loader or awesome-typescript-loader processes JavaScript or typescript files
/ * * * * * * / (function(modules) { // webpackBootstrap./* 0 */
/ * * * / (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony default export */ __webpack_exports__["default"] = ((text = "Hello world") = > {
const element = document.createElement("div");
element.innerHTML = text;
return element;
});
/ * * * / })
/ * * * * * * / ]);
Copy the code
use: [“style-loader”, “csS-loader “] csS-loader will automatically parse @import and URL (), and style-loader will inject CSS into the DOM and implement HMR features. For CSS preprocessors such as SASS and LESS, there is also a special Sass-Loader or less-loader to process them. It is also common to extract CSS into a separate style file in a production environment, where tools such as mini-CSS-extract-Plugin (MCEP) can be used. Similarly, we can use url-loader/file-loader to handle resource files such as images.
The code segment
Code segmentation is an important segmentation to improve Web performance. We often do code segmentation is also divided into common code extraction and on-demand loading and other methods. Common code extraction is to separate the third-party rendering module or library from the logical code of the application itself, or to extract the common code between multiple modules in the application and divide it into independent chunks, so as to facilitate client caching and other operations.
Instead of relying on CommonChunksPlugin for configuration in Webpack 3, Webpack 4 introduces SplitChunksPlugin and gives us out-of-the-box code optimization features, Webpack automatically splits code based on:
- New blocks are shared between modules or come from the node_modules directory;
- The size of the new block should exceed 30KB before compression;
- The number of blocks a page needs to load concurrently should be less than or equal to 5;
- The number of blocks the initial page loads should be less than or equal to 3;
The default SplitChunksPlugin configuration is as follows:
splitChunks: {
chunks: "async".minSize: 30000.minChunks: 1.maxAsyncRequests: 5.maxInitialRequests: 3.automaticNameDelimiter: '~'.name: true.cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/.priority: - 10
},
default: {
minChunks: 2.priority: - 20.reuseExistingChunk: true}}}Copy the code
It is worth mentioning that the chunks option has three configurations: Initial, Async and All. The above configuration is optimized for the initial chunks, the ondemand chunks and all chunks respectively. If vendors’ chunks are set to Initial, it ignores the third-party library code contained in the module package that is dynamically imported. Priority is used to specify the priority of a custom Cache Group capture code, with a default value of 0. In the example of common-chunk-and-vendor-chunk, we optimized the entry and extracted the vendor module and service module common to the entry and exit:
{
splitChunks: {
cacheGroups: {
commons: {
chunks: "initial".minChunks: 2.maxInitialRequests: 5.// The default limit is too small to showcase the effect
minSize: 0 // This is example is too small to create commons chunks
},
vendor: {
test: /node_modules/.chunks: "initial".name: "vendor".priority: 10.enforce: true}}}}Copy the code
Webpack’s Optimization also includes the runtimeChunk attribute, which, when set to true, adds chunks of run-time information only to each Entry; When this property value is set to single, common chunks containing the runtime are created for all entries. We can also use import statements in our code to dynamically divide blocks and load code on demand:
Webpack 3 supports explicit Chunk names
import(/* webpackChunkName: "optional-name" */ './module')
.then(module= > {
/ *... * /
})
.catch(error= > {
/ *... * /
});
Copy the code
webpackJsonp([0] and {KMic: function(a, b, c) {... },co9Y: function(a, b, c) {... }});Copy the code
When developing a React project, it is recommended to use React -loadable for on-demand component loading. It can handle component loading, server rendering, and other scenarios gracefully. Webpack also has built-in support for Tree Shaking optimization based on the ES6 Module specification, which extracts only the required code from imported files.
For more tips on using Webpack, see Webpack CheatSheet or the Modern Web Development Basics and Engineering Practices /Webpack section.
Backpack
Backpack is a minimalist build system for Node.js, influenced by creation-React-app, next.js, and Nodemon, that creates node.js projects with zero configuration. Backpack handles file monitoring, hot loading, transformation, packaging, etc., and supports ECMAScript’s latest async/await, object extension, class attribute syntax by default. We can use NPM to install dependencies:
$ npm i backpack-core --save
Copy the code
Then configure the run script in package.json:
{
"scripts": {
"dev": "backpack"."build": "backpack build"}}Copy the code
A typical use of Backpack can be seen in Backend-Boilerplate/node, or we can override the default Webpack configuration:
// backpack.config.js
module.exports = {
webpack: (config, options, webpack) = > {
// Perform customizations to config
// Important: return the modified config
returnconfig; }};Copy the code
Or add the Babel plugin:
{
"presets": ["backpack-core/babel"."stage-0"]}Copy the code