webpack简介
前端是基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统
Webpack 是当下最热门的前端资源模块化管理和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。通过loader的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。
1.script标签
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>
弊端:
- 全局作用域下容易造成变量冲突
- 文件只能按照
2.CommonJs
允许模块通过 require方法来同步加载所要依赖的其他模块,然后通过 exports 或 module.exports 来导出需要暴露的接口
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;
优点:
- 服务器端模块便于重用
- NPM 中已经有将近20万个可以使用模块包
- 简单并容易使用
缺点:
- 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
实现:
- 服务器端的 Node.js
3.AMD
(Asynchronous Module Definition)只有一个主要接口 define(id?, dependencies?, factory),它要在声明模块的时候指定所有的依赖 dependencies,并且还要当做形参传到 factory 中,对于依赖的模块提前执行,依赖前置。
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });
优点:
- 适合在浏览器环境中异步加载模块
- 可以并行加载多个模块
缺点:
- 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅
- 不符合通用的模块化思维方式,是一种妥协的实现
实现:
- RequireJS
- curl
4.CMD
Common Module Definition 规范和 AMD 很相似,尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性
define(function(require, exports, module) {
var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
优点:
- 依赖就近,延迟执行
- 可以很容易在 Node.js 中运行
缺点:
- 依赖 SPM 打包,模块的加载逻辑偏重
实现:
- Sea.js
- coolie
ES6
ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量
import "jquery";
export function doStuff() {}
module "localModule" {}
优点:
- 容易进行静态分析
- 面向未来的 ECMAScript 标准
缺点:
- 原生浏览器端还没有实现该标准
- 全新的命令字,新版的 Node.js才支持
实现:
- Babel
**如何做到让 require 能加载各种资源呢?
webpack孕育而生**
webpack命令行实践
mkdir webpack
cd webpack
npm init
npm install webpack --save-dev
新建一个hello.js
* useage:webpack 需要打包的文件 打包后的文件
* webpack hello.js hello.bundle.js
* Asset: 打包后的文件名
* Size: 打包后的文件大小
* chunks: 打包的分块
* chunks name:分块的块名称
新建一个hello.css
方式一:
npm install -D style-loader css-loader
引入import ('style.loader!css-loader!./hello.css')
方式二:
webpack hello.js hello.bundle.js --module-bind 'css=style-loader!css-loader' --watch --progress --display-reasons
方式三:
使用配置文件 to be continue
使用配置文件
配置node脚本
package.json
{
"scripts":{
"webpack": "webpack --config webpack.dev.js --display-moudles --display-reasons --color"
}
}
执行
npm run webpack
四个核心概念:
- 入口(entry) : 图表的起点被称之为入口起点
- 输出(output) : 描述了如何处理归拢在一起的代码
- loader : 将webpack不能理解的文件转换为模块,并添加到依赖图表中
- 插件(plugins) : 常用于(但不限于)在打包模块的“compilation”和“chunk”生命周期执行操作和自定义功能
entry
简单用法
const config = {
entry: './path/to/my/entry/file.js'
};
module.exports = config;
常用语法
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
多页面应用
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
output
path:文件路径
filename:文件输出的名字
puchlicPath:根路径
占位符如下
* [id] 被 chunk 的 id 替换。
* [name] 被 chunk 的 name 替换(或者,在 chunk 没有 name 时使用 id 替换)。
* [hash] 被 compilation 生命周期的 hash 替换。
*[chunkhash] 被 chunk 的 hash 替换。
const config = {
output: {
filename: '[name].bundle.js',
path: '/home/proj/public/assets'
publicPath: 'https://www.cdn.com/'
}
};
module.exports = config;
loader
loader特性
- loader从右到左链式调用。在最后一个 loader,返回 webpack 所预期的 JavaScript。
- loader 可以是同步或异步函数。
- loader 运行在 Node.js 中,并且能够执行任何可能的操作。
- loader 也能够使用 options 对象进行配置。
- loader 能够产生额外的任意文件。
配置loader
1.安装依赖包
npm install -D style-loader css-loader
2.配置webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.css$/,
use: ['style-loader','css-loader']
}]
}
}
plugin
const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const config = {
...
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
vue-cli配置分析
https://github.com/DDFE/DDFE-blog/issues/10
webpack源码分析
https://github.com/DDFE/DDFE-blog/issues/12
- 执行 bin 目录下的 webpack.js 脚本,解析命令行参数以及开始执行编译。
- 调用 lib 目录下的 webpack.js 文件的核心函数 webpack ,实例化一个 Compiler,继承 Tapable 插件框架,实现注册和调用一系列插件。
- 调用 lib 目录下的 /WebpackOptionsApply.js 模块的 process 方法,使用各种各样的插件来逐一编译 webpack 编译对象的各项。
- 在3中调用的各种插件编译并输出新文件。