[TOC]
## 前言
webpack作为当下最流行的前端打包工具,如果你对它还一无所知,那就可能找不到一份好的工作?其实我们学习或者不学习不仅仅因为某个公司是否在用这个框架,更要因为使用这个框架具有什么特点,能帮我们解决什么问题,会带来其他什么问题,使用成本如何,难度如何,可拓展性如何。
## 使用场景
在前端生态日益完善的今天,各种针对前端工程化提出的解决方案层出不穷,这些方案一般都能大幅度的提高或者改善我们的开发过程,但是却可能不能直接用于生产环境使用,这些方案可能有:
* js模块化,针对工具性质的、ui性质的组件模块化开发
* es6或者typescript语言编写的程序
* 样式预处理器比如less sass编写的样式
* html模板引擎比如jade等
综上:这些开发阶段使用的技术产物不能直接用于生产环境部署使用,我们手动去操作这些又过于繁琐,所以提出来webpack这一个工具,可以实现将一切资源进行配置化打包的思想,来简化我们的工作。
## 是什么,与其他工具什么区别
* 概念理解
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。换句话说,它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
* 图解webpack以及与其他框架的对比
![图解各个工具](http://pic4.zhimg.com/v2-ae9253e557d902369b1beaed998061cb_b.jpg)
* 表格说明
| 名称 | 类型 | 特点描述 |
| --- | --- | --- |
| grunt | 前端流程工具 | 基于配置,较繁琐 ,需要不断的修改配置文件,入手难度大 |
| gulp | 前端流程工具| 基于管道,基于stream,非常快,更加便利,可以灵活的把若干插件配置到管道任务中 |
| browserify | 预编译模块化方案 | |
| seajs/requirejs | 在线模块化方案 | 通过引入,在线把你的文件进行模块化,不同的只是两个的模块规范不同 |
| webpack | 预编译模块化方案 | 更加智能化 , |
* 工作流程区别
![](https://box.kancloud.cn/e192ecba0ea28f9a7c938a6660954103_1240x446.png)
![](https://box.kancloud.cn/5594f7e3f87162c57ef4de06b22f5c9b_1240x543.png)
* [与其他工具的区别](https://survivejs.com/webpack/appendices/comparison/)(如果你外语水平有限,建议chrome打开,然后右键翻译为中文)
* 优点
> **代码拆分**
Webpack 有两种组织模块依赖的方式,同步和异步。异步依赖作为分割点,形成一个新的快。在优化了依赖树后,每一个异步区块都作为一个文件被打包。
**Loader**
Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。
**智能解析**
Webpack 有一个智能解析器,几乎可以处理任何第三方库,无论它们的模块形式是 CommonJS、 AMD 还是普通的 JS 文件。甚至在加载依赖的时候,允许使用动态表达式 require("./templates/" + name + ".jade")。
**插件系统**
Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。
**快速运行**
Webpack 使用异步 I/O 和多级缓存提高运行效率,这使得 Webpack 能够以令人难以置信的速度快速增量编译。
## 能解决什么问题
webpack简单点来说就就是一个配置文件,所有的魔力都是在这一个文件中发生的。 这个配置文件主要分为三大块:
> entry 入口文件 让webpack用哪个文件作为项目的入口,所有的项目主要通用依赖通过这个文件作为入口,其他跳转的页面依赖的资源在单独的组件中去加载。
> output 出口 让webpack把处理完成的文件放在哪里
>module 模块 要用什么不同的模块来处理各种类型的文件
## 如何使用
### 准备工作
* 安装webpack
~~~
//全局安装
npm install -g webpack
//安装到你的项目目录
npm install --save-dev webpack
~~~
* 项目初始化
~~~
//填写基本的项目信息,会生成一个package.json的文件,如果有这个文件忽略
cnpm init
// webpack安装到包依赖之中,可以安装稳定版本的,webpack@1.12.x
npm install --save-dev webpack
~~~
* 项目结构
建立两个文件夹,app以及public,app文件夹用来存放原始数据和我们将写的JavaScript模块,public文件夹用来存放之后供浏览器读取的文件(包括使用webpack打包生成的js文件以及一个index.html文件)。接下来我们再创建三个文件:index.html --放在public文件夹中;module.js-- 放在app文件夹中;main.js-- 放在app文件夹中;
此时的项目结构如图所示:
![](https://box.kancloud.cn/5d78720f959ec64b84a7dffc0dfbe57f_386x187.png)
* 初始化一些文件内容
1.我们在index.html文件中写入最基础的html代码,它在这里目的在于引入打包后的js文件(这里我们先把之后打包后的js文件命名为bundle.js,之后我们还会详细讲述)。
~~~
<!DOCTYPE html>
<html>
<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>webpack demo文件</title>
</head>
<body>
<div id='app'>
</div>
<script src="bundle.js"></script>
</body>
</html>
~~~
2.在module.js中定义一个返回包含问候信息的html元素的函数,并依据CommonJS规范导出这个函数为一个模块:语法中我们可以充分利用es6的常量,模块,模板字符串,解构等语法,非常方便。(创建文件可以用`pico filename`)
~~~javascript
// module.js
const HELLO="Hello word!";
var hello= function(name) {
var greet = document.createElement('h1');
greet.textContent =`HELLO${HELLO}`;
return greet;
}
module.exports = {
hello
}
~~~
3.main.js文件中我们写入下述代码,用以把module模块返回的节点插入页面。
~~~
const {hello}=require("./module");
document.querySelector("#app").appendChild(hello('zhangsan'));
~~~
* 终端使用webpack模块
备注:无论哪种环境中,文件路径是必备的常识,如果你不太清楚绝对路径,相对路径,根路径请参考我另外一篇技术文档,点击跳转。
~~~
# {extry file}出填写入口文件的路径,本文中就是上述main.js的路径,
# {destination for bundled file}处填写打包文件的存放路径
# 填写路径的时候不用添加{},建议在项目根目录下的文件地址最前面不用加任何路径
webpack {entry file} {destination for bundled file}
webpack 'app/main.js' 'public/bundle.js'
~~~
编译成功后查看页面,已经生效并打包到了对应文件中。从这个结果中可以看到,webpack只能适用于将某些资源打包为一个模块,用于一个页面中,如果你想批量操作打包或者引入文件,还是需要gulp辅助。(在打包成功的报文中,我们可以看到,Webpack 会分析入口文件,解析包含依赖关系的各个文件。这些文件(模块)都打包到 bundle.js 。Webpack 会给每个模块分配一个唯一的 id 并通过这个 id 索引和访问模块。在页面启动时,会先执行 entry.js 中的代码,其它模块会在运行 require 的时候再执行。)
![](https://box.kancloud.cn/fa82150ffb73813530ff6a77354b0627_1000x250.png)
![](https://box.kancloud.cn/3fd8002d1df423cc7c2e240d1e89946d_421x112.png)
* 使用配置文件进行打包
虽然可以使用终端工具以及对应的模块可以进行很多操作,但为了方便管理,我们还是把这部分操作放在了文件中,比如loader,plugin等。在当前练习文件夹的根目录下新建一个名为webpack.config.js的文件,我们在其中写入如下所示的简单配置代码,目前的配置主要涉及到的内容是入口文件路径和打包后文件的存放路径。
~~~
//注:“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录。
module.exports = {
entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后输出文件的文件名
}
}
~~~
有了这个配置之后,再打包文件,只需在终端里运行webpack命令就可以了,这条命令会自动引用webpack.config.js文件中的配置选项,省略了若干的参数。
进一步简化:你可以通过修改package.json文件中的scripts来把一些常用命令放到npm命令中,比如写入`"start":"webpack"`就可以通过npm start就实现webpack打包。
* 拓展阅读
scripts属性可以自定义很多你想要的任务,其中start是比较特殊的,定义之后直接运行npm start,其他的则需要通过`npm run task`,如果你不清楚有哪些可执行命令,可以通过`npm run` 得到所有的可执行命令列表:
![](https://box.kancloud.cn/cc0b4801c639bdf3c8fd002c13ca031b_436x99.png)
### 正式使用强大功能
#### 生成Source Maps(使调试更容易)
通过简单的配置,webpack就可以在打包时为我们生成的source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。
在webpack的配置文件中配置source maps,需要配置devtool,它有以下四种不同的配置选项,各具优缺点,描述如下:
| devtool选项 | 配置结果 |
| --- | --- |
| source-map | 在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的<code>source map</code>,但是它会减慢打包速度 |
| cheap-module-source-map | 在一个单独的文件中生成一个不带列映射的<code>map</code>,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便; |
| eval-source-map | 使用<code>eval</code>打包源文件模块,在同一个文件中生成干净的完整的<code>source map</code>。这个选项可以在不影响构建速度的前提下生成完整的<code>sourcemap</code>,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定不要启用这个选项; |
| cheap-module-eval-source-map |这是在打包文件时最快的生成<code>source map</code>的方法,生成的<code>Source Map</code> 会和打包后的<code>JavaScript</code>文件同行显示,没有列映射,和<code>eval-source-map</code>选项具有相似的缺点; |
> 以上文件从上到下,打包越来越快,中小项目我们一般使用eval-source-map,大型项目为了降低成本,我们可以使用cheap-module-eval-source-map。对应的配置写法:`devtool: 'eval-source-map',`加了这个配置之后就可以看到你开发的源文件,找到其代码,不加的话是看不到原开发代码文件,只有压缩文件显示的。
> `module.exports = { devtool: 'eval-source-map'}`
![](https://box.kancloud.cn/59f5a4d5e1fdb8e219df787d76da4b8d_709x320.png)
#### 使用webpack作为本地服务器
* 基本使用
浏览器监听你的代码的修改,并自动刷新显示修改后的结果,使用并配置webpack-dev-server即可。需要将它加入到项目依赖。点击查看[官网配置说明](https://webpack.js.org/configuration/dev-server/)。
这里只说明比较重要的几个配置,port:8080,访问端口,默认为8080,如果你同时开发两个应用,端口要修改其中一个。
~~~
// 终端安装模块
cnpm i webpack-dev-server
//webpack中配置dev-server
devServer: {
contentBase: "./public",//本地服务器所加载的页面所在的目录
historyApiFallback: true,//不跳转
inline: true//实时刷新
}
//package.json中配置启动脚本
"server":"webpack-dev-server --open"
// 启动服务器
cnpm run server
~~~
* 可能遇到的问题:
1.开启错误 提示地址解析错误`getaddrinfo ENOTFOUND localhost`。解决办法:设置host文件`127.0.0.1 localhost`的映射
2.如果你不想每次启动都打开一个窗口,设置:`open:false`,否则设置true则默认打开
3.希望时时更新展示 inline:true ,那么更新内容后会时时更新页面部分得到打包后的结果
#### 使用babel转化
babel的用途:可以使用最新的js语言版本;可以支持js拓展之后的语言比如jsx。(潜在的原因是因为浏览器不支持部分es6的语法,需要通过babel把它转化为es5,如果不用原来的es6语法就会保留,旧版浏览器不支持就会出现报错)。babel具有非常多的配置选项,在单一的webpack.config.js文件中进行配置往往使得这个文件显得太复杂,因此一些开发者支持把babel的配置选项放在一个单独的名为 ".babelrc" 的配置文件中
~~~
// npm一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
// 配置babel的解析器 其中 resolve是解析路径的
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader",
},
include:[resolve('app'), resolve('test')],
exclude: /node_modules/
}
]
}
//.babelrc
{
"presets": ["react", "es2015"]
}
~~~
* 注意事项
每一项后缀名的文件都需要追加其对应的loader,否则就会提示你需要正确的loader加载它,导致打包失败。所以对于文件中有多少文件类型需要追加loader都需要详细区分。
`error:You may need an appropriate loader to handle this file type`.
## 参考入门项目
* [webpack-demo项目](https://github.com/robinson90/webpack-demo.git)
## 建议
目前三大框架都有基于webpack做的较好的脚手架,如果自己不是特别想钻研或者浪费时间的话,建议直接基于脚手架开发自己的项目,如果对应的配置环境不够,自己根据prod的部分额外增加几个配置即可。
- [create-react-app](https://github.com/facebook/create-react-app)
- [vue-cli](https://github.com/vuejs/vue-cli/)
- [angular-cli](https://github.com/angular/angular-cli)
## 参考文档
* [github官网地址](https://github.com/webpack/webpack)
* [webpack2.0中文文档](http://www.css88.com/doc/webpack2/guides/development/)
* [webpack入门--张旺--推荐阅读](http://www.jianshu.com/p/42e11515c10f)
* [webpack入门到工程化实践--张旺](http://mp.weixin.qq.com/s/5v7x8tzZzTmB8v5ComfiSA)
* [webpack入门教程(菜鸟教程)](http://www.runoob.com/w3cnote/webpack-tutorial.html)
* [webpack是什么?(http://www.css88.com)](http://www.css88.com/archives/6992#more-6992)
* [webpack知乎傻瓜指南](https://zhuanlan.zhihu.com/p/20367175)
* [极客学院webpack教程](http://wiki.jikexueyuan.com/project/webpack-handbook/)
* [webpack3系列教程](https://www.rails365.net/groups/webpack)
* 掘金小册 webpack教程
* [从入门到工程实践](https://mp.weixin.qq.com/s/5v7x8tzZzTmB8v5ComfiSA)
- 前端工程化
- 架构总纲
- 001
- 美团技术架构
- 前端工程化说明
- 历史背景说明
- 架构说明
- 前端工程化技术栈
- 技术文档说明
- 功能模块说明
- 前端模块管理器简介
- 框架对比分析
- vue&react&ng对比分析(一)
- vue&react&ng对比分析(二)
- vue&react&ng对比分析(三)
- 工程化专题系列
- 需要解决的问题
- 001
- 002
- 003
- 常见代码错误
- jslint中常见的错误
- css规范常见错误
- html规范常见错误
- 工程化目录
- 工程化初始化
- 项目构建流程
- 项目打包优化
- 上线与迭代注意事项
- 前端部署发布
- jetkins部署
- 部署需求整理
- 前端监控
- 工程化实践指南
- dock持续部署
- 系列文章
- 插拔式前端的设计
- 其他实践
- 工程化的前端管理
- 宋小菜借鉴
- 大前端团队介绍
- 人员组成
- 人员发展
- 研发流程
- 任务分类
- 前端基础建设与架构
- 技术栈以及技术方案
- 业务目录大纲
- 前端大纲
- api管理
- 后端api工具
- 前端easymock
- api拦截与代理
- api优化
- api请求时长策略设计
- 前端架构专题
- 架构专题一
- 产品原型对接
- 与ui对接
- 图片专题
- 图片工程化大纲
- 图片优化
- 图标字体
- 图标字体vs雪碧图
- 工程化的前端矩阵
- 蚂蚁金服前端矩阵分享
- BFF架构
- 概念解析
- 前端脚手架
- 初始化项目
- 个性化配置
- 部署与发布
- 性能优化专题
- http专题
- https常识
- http优化1
- http优化2
- http优化3
- http缓存
- 常规web性能优化攻略
- 性能优化大纲
- 样式优化
- js优化
- 第三方依赖优化
- 代码分割优化
- 图片优化
- 打包优化
- 服务器优化
- 缓存优化
- 交互优化
- pc事件优化
- 手机事件优化
- 推荐文章
- 01
- 前端安全专题
- 前端安全大纲
- 前端第三方库
- seo优化
- web框架的对比
- 001
- 学习资源
- 珠峰前端架构
- npm教程
- npm入门
- cnpm入门
- cnpm搭建
- 你该知道的js模块
- browserSync
- opn
- js-cookie
- npm-script进阶
- 入门篇
- 进阶篇
- 高阶篇
- 实践篇
- yarn入门
- nodejs教程
- axios&&fetch
- xhr
- axios
- fetch
- babel专题
- babel入门
- profill入门
- nodejs入门
- 快速入门
- 大纲介绍
- node基础
- global obj
- assert断言
- procss-进程
- child_process子进程
- cluster集群
- console控制台
- crypto-加密
- dgram-数据报
- dns-域名服务器
- error-异常
- events-事件
- global-全局变量
- http-基本协议
- https-安全协议
- modules-模块
- os-操作系统
- path-路径
- querystring-查询字符串
- readline-逐行读取
- fs-文件系统
- net-网络操作
- 命令行工具
- 内存泄露
- 代码的组织与部署
- 异步编程
- orm模块
- 异步编程解决方案
- node-lessons
- 环境准备
- nodejs实践
- 项目搭建
- 异步优化
- 创建web和tcp服务器
- 终端问答程序
- 爬虫系统
- mongleDb
- mongoDB简介
- 基本使用
- 实用技巧
- 汇总001
- 饿了么后台搭建
- nodejs干货
- 沪江基于node的实践
- 苏宁基于nodejs优化
- 基于nodejs开发脚手架
- 书籍干货
- 深入浅出nodejs
- 异步I/O(一)
- gulp教程
- gulp入门
- gulp常用插件(1)
- gulp常用插件(2)
- gulp创建目录
- 经验普及贴
- webpack教程
- webpack入门
- 简单入门
- entry配置
- output配置
- 插件使用01
- 插件使用02
- loader使用
- dev-server介绍
- 构建css
- css模块化
- 使用less和sass
- 构建图片
- 引入字体
- babel配置攻略
- eslint
- 001
- webpack进阶
- 分不同文件检出
- 优化打包大小
- 优化打包速度
- 自定义配置
- 单页以及多页如何配置
- 优化实践
- 文章导读
- 001
- 优化指南
- 参考列表
- webpack4
- 多入口程序构建
- 参考教程
- 项目实践
- 环境区分
- 常见问题
- 解读webpack
- 从vuejs权威指南中解决
- 深入浅出webpack
- rollup
- 入门
- parcel
- 入门篇
- express教程
- nuxt教程
- 入门
- 基本入门
- koa教程
- koa基本入门
- koa开发注意事项
- koa实践指南
- 关于路由
- koa优化指南
- 001
- Vuejs
- vuejs入门系列
- vue-cli入门
- vue2基本认识
- vuejs入门教程
- 样式绑定
- vuex入门学习笔记
- vue组件生命周期
- 组件的使用
- vue-router入门
- vue-filter
- 计算属性使用
- 开发注意事项
- mixins
- 组件通讯
- vuejs进阶
- 进阶资源
- router进阶
- 官网介绍
- 前进与后退优化
- keep-alive基本使用
- keep-alive原理详解
- 钩子函数进阶
- 计算属性&监听&方法
- vue服务端渲染技术
- 项目实践之路
- 实践大纲
- 插槽专题篇
- vue-cli升级
- 进阶入门
- vuejs架构
- nuxt
- vuejs项目实践
- vue实践常见问题
- 001
- 002
- 003
- 004
- 005
- 改造api参数探索
- 007
- 008
- 009
- 010
- 项目技术栈
- vue性能问题以及优化方案
- vue-spa应用的理解
- vue-ssr的部署与使用
- 滴滴出行实践案例
- 2.0重构
- vue-element-admin实践
- 准备工作
- 菜单设计
- 权限设计
- 依赖模块
- vue-betterScroll
- 性能优化懒加载
- 京东组件实践
- vue2项目小结
- vue探索与实践
- 去哪实践
- 介绍
- 饿了么项目实践
- 项目解析
- vue骨架屏实践
- vue生态推荐
- ui框架
- elementUI
- 001
- 002
- VUE-material
- vant-ui
- 解读入门
- iview
- 使用问题汇总
- vux
- mint-ui
- loadmore
- vue资源导航
- vueconf
- 源码解读
- vm
- 双向绑定
- 基本原理
- 数组双向绑定
- 报错机制
- 封装方法
- 运行环境
- 入门
- 指令
- vue-router解读
- util
- vue-props
- 流程逻辑
- 推荐文章
- 源码解读
- 文章导读
- 001
- vuejs实战
- 基础篇
- 进阶篇
- 实践篇
- 面试专题
- angularjs教程
- angularjs入门系列
- 基本入门
- ng2入门
- ng进阶
- ng项目实践
- 源码解读
- typescript
- reactjs教程
- reactjs入门系列
- react的基本入门
- react组件
- virtalDom认识
- react-cli入门
- react组件的生命周期
- 基本知识点
- react-router教程
- react进阶
- 基本实践
- react加载性能优化指南
- react属性封装
- 进阶45讲
- 01概述
- 02jsx
- 06高阶组件&函数子组件
- contextApi
- react-router
- 入门章节
- 进阶
- 高阶组件
- react进阶组件
- 基本介绍
- render props
- render props的封装
- render props getter
- react-native入门
- 源码解读
- 001
- 002-reactDemo
- 参考教程
- 参考教程1
- 了解react-hooks
- ui框架
- pc端ui框架推荐
- 项目实践
- weatherApp
- 001
- 002
- 不同生命周期使用场景
- react项目结构和组件的命名
- 常见问题解答
- 参考书籍
- react全栈
- 前言
- react与redux进阶
- 常见误解
- 反模式
- react设计模式与最佳实践
- 7美化组件
- 7.2行内样式
- 7.4css模块
- 深入react技术栈
- react学习手册
- 序
- mobx教程
- 入门
- 大佬推荐
- 001
- react面试
- 001
- linux教程
- linux入门
- 基本入门
- 文件管理
- 文件传输
- 文档编辑
- 磁盘管理
- 磁盘维护
- 网络通讯
- 系统管理
- 系统设置
- 备份压缩
- 设备管理
- 查看系统信息
- linux其他
- webhook
- rsync入门教程
- ssh免登陆设置
- 安装nodejs
- nginx教程
- 入门教程
- 安装
- 基本配置
- 服务基本使用
- 高性能nginx
- 001
- pm2教程
- shell教程
- 入门大纲
- echo命令
- 参考文献
- linux常用命令2
- linux常见问题
- 001
- python
- 入门教程
- 机器学习
- 准备工作
- 服务器常识
- tomcat
- 入门常识
- iis
- redis教程
- 入门第一篇
- redis进阶
- 项目实践
- redis使用问题
- mongleDB
- 入门
- 使用进阶
- 项目实践
- 常见问题
- electron
- 入门系列
- 前言
- 小程序
- 入门
- 准备工作
- 路由
- 参考文档
- 001
- 小程序开发--双路视频调研
- 准备工作
- 参考资源
- 参考网址
- docker
- 入门
- 基本认识
- 安装与使用
- docker安装nginx
- docker安装jetkins(1)
- docker部署jenkins(2)
- 进阶
- 实践总结
- docker群分享
- docker部署前端应用
- 文章导读
- docker其他
- 网络安全
- 入门
- 大纲
- 项目解析
- schoolpal.web
- 功能模块大纲
- 目录结构大纲
- 前端国际化
- 国际化方案
- 其他
- bower入门教程
- weex
- 入门
- memcached
- 入门
- sails
- 入门