本文是混子前端以前在学习 webpack 时整理的说明文件 有些枯燥 但整理的很详细,其中代码模块我已图文备注说明,若是你刚开始准备学习 webpack 那本文对你帮助很大,必定要按照文字走彻底流程
webpack基本介绍
webpack: 给js准备的一个打包工具,能够把不少模块打包成不多的静态文件,有一个本身的特性:代码分割 (code splitting),还有一个loaders的概念,模块是经过loaders处理各类文件,不管js是用 commonJS、AMD、ES六、CSS、Images、JSON、Coffeescript、LESS... 均可以用loaders 处理,甚至还能够是本身定义的一些文件,如:.vue、.JSX文件均可以经过 loaders 处理css
代码分割: 可使项目加载过程当中只去加载一些当时只须要的部分文件
webpack官方:就是一个模块打包器,下图左边箭头表示文件之间依赖关系的模块群,这样的模块群经过 webpack 打包以后,对依赖进行处理把他打包成能够直接运行的 js/css/图片 文件

webpack目标:
- 会切分依赖树,会把依赖树切分不一样代码块里,而后按需加载依赖,和前端懒加载概念类似
- 保持初始化加载时间更少
- 任何静态资源均可以视为一个模块在项目中引用,在开发中起到不少便利,整合第三方类库,把第三方类库视作模块在项目中引用
- 能够在整个打包过程当中,每一步均可以自定义去作事情
和其余打包工具不一样 gulp/grount
- code Splitting 代码分割
- loaders
- 插件系统,模块热更新 plugin system:在开发过程当中提升开发和调试效率
核心思想:
打包原理:
bundle.js 是以模块 id 为记号,经过函数把各个文件 依赖封装 达成分割效果
webpack安装和命令行
> mkdir webpack-test //建立webpack-test文件夹
> npm init //初始化项目,建立package.json文件
> npm install webpack@3.0.0 --save-dev //安装3.0版本webpack,由于4.0版本直接打包会报错,比较严格
> 建立hello.js 和 world.js,用commonJS规范在hello.js require world.js
> webpack hello.js hello.bundle.js //打包hello.js文件
观察hello.bundle.js:

html
能够看到world代码被打包进来了,编号是 1,写在 hello.js 中的 require 被替换成webpack_require,webpack用这种方式去寻找依赖,把文件打包到一块儿,这是简单工做方式
前端
> 继续建立 style.css 文件,在 hello.js 中 require style.css (不深究为何),执行打包命令:webpack hello.js hello.bundle.js 开始报错,提示没有安装 css loader,由于他不支持打包 css类型,若是打包 css 文件须要安装 css loader
> npm install css-loader style-loader --save-dev
> 执行打包命令仍是会报错,由于在 hello.js 中 require style.css 没有执行loader,须要写成require('css-loader!./style.css'),意思是:在引用style.css文件前必须通过css-loader处理,继续执行打包命令,没有报错
> 建立 index.html 引用hello.js文件,而且在 style.css 中给 body 添加 background 属性,发现执行打包命令后颜色没有效果,要想颜色有效果要结果style-loader,在hello.js中改成require('style-loader!css-loader!./style.css')
能够看出css-loader让webpack去处理css文件,style-loader经过css-loader处理完的文件,把处理完的文件新建一个style标签插入到html head里面
> 若是在代码里每次 require css 都须要写一长串的话 style-loader!css-loader! 的话会很麻烦,也能够用打包命令:vue
webpack hello.js hello.bundle.js --module-bind 'css=style-loader!css-loader'react
用到了webpack中 --module-bind 的参数,至关于把这个模块绑定:若是是css文件就先交给css-loader,css-loader以前要style-loader
webpack
> 若是每次改变都须要打包的话,会很麻烦,能够用--watch参数监听:
webpack hello.js hello.bundle.js --module-bind 'css=style-loader!css-loader' --watches6
> 除了--watch还有一些其余参数,如:
一、--progress : 看到打包的百分比;web
二、 --display-modules:看到打包的模块和用到的loader列出来;npm
三、--display-reasons:打包 模块的缘由列举出来json
创建项目的webpack配置文件
创建 webpack.config.js 缘由:若是直接使用 webpack 命令,会直接在项目根目录寻找webpack.config.js 做为默认配置去运行,这时不须要指定任何参数,会直接读取 config 里面的内容,也可使用 --config 指定其余配置文件
即:执行 webpack 会去项目目录找 webpack.config.js 文件,若是配置文件不叫这个名字 (假如修改成webpack.dev.config.js),能够执行 webpack --config webpack.dev.config.js,也可生效
若是想在webpack命令行中加入一些参数,能够借助 package.json 中 script 属性

webpack配置的entry和output
一、entry 打包2个平行的js文件能够写成数组模式

打包后的 bundle.js 文件

这个0模块把两个不相干的模块,require 打包到一块儿,这样就能够在开发中使用
二、在多页面应用程序,能够用到entry为对象的形式,对象的key是 chunk name,value 是entry,根据不一样页面分配不一样的 chunk,若是 entry 的 objcet 是多余一个的,那打包好的文件就不能够是一个了,这时候就要修改 output,在 output 中修改 filename 属性,这里若是指定了 hash,以下图:
打包后的多个文件 hash 值都同样,因此引出了 chunk-hash,以下图:
若是每次打包生成的惟一加密(md5)后 chunk-name不同,那 html 文件中引入的也不同了,因此这里要加入插件
html-webpack-plugin,在项目中 npm 安装,在 webpack.config.js 中配置,以下图:

这时候运行 npm run webpack,会生成打包好 带有 hash 值的 main.js 和 a.js 文件,还有新的html 文件引入了带有 hash 值的压缩文件,以下图:

插件生成的 index.html 和项目根目录的 index.html 没有任何关系,这不知足需求。若是以根目录index.html去生成dist下index.html,就要在 webpack.config.js 中继续操做

这时就能够把根目录下 index.html 中 script src 标签删掉,打包后的 index.html 会自动引入压缩并带有 hash 值的 js 文件,这时候发现一个问题,全部压缩好的文件都在dist/js下,这和实际生产不符,实际须要 index.html 在 dist/js 目录外的,还要去修改 webpack.config.js,将不是 js 文件都建立到 dist 目录,将js文件 filename 指定相对路径

打包后文件结构以下图:

除了 template 还有一些其余参数:
如何作到在 webpack.config.js 中修改 index.html 文件 title
index.html中:

还能获取到哪些参数:

index.html 中:

打包编译后为:

究竟能从 htmlWebpackPlugin 取到哪些信息?
这时候能够对 htmlWebpackPlugin进行遍历,由于相似于模版文件引擎写法,能够直接编写:

在打包后生成的 index.html 中能够看到:

继续遍历 files 和 options 能够拿到不少配置信息,不一一介绍了,能够去 npmjs.com 搜索html-wekpack.plugin 进行查看

继续探索,假如想把一部分 js 放到 index 的 head 标签里,一部分想放到 body 标签里,只经过配置是作不到的,因此要改变模版:
一、将 webpack.config.js 中 inject 修改成 false

二、编写 script 标签 src 便可

继续探索,假如打包后要上线,上线后的地址和本地的相对路径确定不同,这时候要借助output 新属性:[[ publicPath ]]
打包后前缀就变了:

上线要对 html 文件进行压缩,就要用到新属性:[[minify]] 对当前生成的html进行压缩

处理多页面应用:须要有多个页面,须要生成多个html:
plugins是一个数组,能够有多个,每个对应一个页面,直接 npm run webpack 便可生成多个html,注意这里新的参数 chunks/excludeChunks

若是但愿把页面性能达到极致,把一些初始化脚本直接嵌入到页面,而不是连接的形式引入到页面,如今全都是连接,即:script src=***,这样能够达到效果但会增长http请求,如今能够把初始的代码直接inline入到页面,能够大大提升运行速度,由于没有http请求:
经过 htmlWebpackPlugin.files.chunks.main.entry 截取掉占位符
后经过 comilation.assets[*****] 取 source() 方法,这是引用公共类库 mian.js 的方法,a/b/c 还有属于本身的js方法,要引入body标签中,这时候修改 webpack.config.js 是没有用的,要在index.html 中写入 js 引入外部文件

webpack如何处理想要的资源文件
转换es6:
npm install --save-dev babel-loader babel-core
bebel-loader: es6不断的修订,经过指定persets来告诉babel-loader转换某一些特性为咱们的js,若是指定全部的特性能够直接用latest,怎么指定插件呢?给loader指定参数,这里指定lastest,而后安装。

官网还提供一种方式指定 persets,能够项目根目录建立 .babelrc 文件,而后指定也能够

还有一种方式能够在 package.json 里面,直接定义 babel,能够不在配置文件里指定

babel-loader 打包编译是很慢的,官网给出新的参数
exclude:loader 的排除范围(不明显)
include:loader的处理范围

exclude 比较慢的缘由是没有用到绝对路径,在项目中怎么获取到绝对路径?
一、须要借助 path 方法

二、path.resolve(__dirname,'相对路径'),resolve解析

同理 include也是写绝对路径
如何在项目里处理css文件?
首先要在命令行中:npm install style-loader css-loader --save-dev
建立一个common.css文件,import到app.js文件中

在webpack.config.js中添加loaders

最后npm run webpack便可,接下来查看,若是有一个须要兼容性的样式怎么处理?假如说:display:flex要咱们手动添加前缀进行兼容,如今有一个loader去处理
npm install postcss-loader --save-dev
postcss-loader是css的一个后处理器,安装好以后,须要继续安装 autoprefixer 这是给postcss的插件,是用来处理css前缀的
npm install autoprefixer --save-dev

这时候 npm run webpack,能够在网页源码中看到生成出来兼容性的css

若是在 css 中使用@import一个文件,会发现display:flex没有生成兼容性的前缀,也就是说他通过了css-loader和style-loader,没有通过postcss-loader,处理办法是借助precss插件,在项目中安装:npm install precss --save-dev

在 postcss-loader 添加配置便可
如何在项目里处理less文件,先安装 less-loader 和 less,进行配置
npm install less-loader --save-dev npm install less --save-dev
和处理css文件的配置同样,不过多了 less-loader,一样要处理css代码兼容性,官方指定,postcss-loader 处理要在 less-loader 和 css-loader 中间进行,顺序不能变

这里若是在 less 中使用 import 写法,能够不用写 require('precss'),由于 less-loader 已经帮咱们作了处理,若是使用sass做为项目预处理器使用方法与less同样
如何处理项目中模版文件,一般是:
一、用webpack把模版文件看成字符串处理
二、webpack把模版文件 当成已经编译好的模版处理函数;首先安装html-loader
npm install html-loader --save-dev
将模版js文件引入css less 及 html模版,咱们在入口app.js文件中引入html模版文件,在webpack.config.js 中添加 html-loader 语法规范便可运行

如今若是,模版文件不是以html结尾,而是以.tpl结尾的模版文件,那要如何处理 ?
首先要引入新的loader:
npm install ejs-loader --save-dev
而后在webpack.config.js中添加规则,让.tpl结尾的文件用 ejs-loader 处理

修改模版文件(是ejs模版引擎的语法,在模版区间内能够自由编写js语法):

而后规则不变,在layer.js引用,这时tpl就不是字符串了,而是返回的函数:

因此在app.js中能够进行传参的方式对模版内name 和 arr进行定义

打包后页面输出:

如今比较流行的loader,好比JSX是react框架的loader,如今这个loader已经被集成到了babel,只须要进行一些设置就能够支持JSX,如今VUE2.0也能够经过直接写render函数,render函数也支持JSX语法
如何处理项目中的图片文件,分几种状况,
一、css中不少的background图片
二、模版结构里引用了img文件
三、根部index.html引用了img文件
首先
npm install file-loader --save-dev
处理第一种状况,在 webpack.config.js 中添加 file-loader 规则:

当给项目增长一个对图片的处理规则,在项目中根目录下 index.html 相对路径图片的引用,仍是css背景中 相对路径图片引用,loader都会帮咱们处理
还有一种状况是模版组件中引用了img文件,会在控制台中看到index.html中img src路径 和 css中 background url 都被替换了,但模版中的img src路径没有被替换,
解决办法:
一、尽量在模版中使用绝对地址
二、能够在src中使用${ }的形式把图片引用进来,这时能够在控制台中看到图片地址被替换了

图片打包之后的输出地址,默认放到了dist目录下,能够给loader添加一些参数:

介绍一个新的loader,npm install url-loader --save-dev,当图片或者文件大小大于指定的limit 指定的大小,会丢给 file-loader 去处理,当小于limit设置值的时候会把图片或者文件转为base64 位编码

这两种方式各有优劣:经过 http 请求载入过来的图片,可让浏览器享受一个优点就是图片的缓存,当图片重复性很高的时候,经过http request下次访问会很快,利用这个缓存;若是是base64,至关于在任何地方用到这个图片时候,在这个地方会有一份一样大小的 base 64 编码存在,会致使代码体积。真正在项目中要平衡的去看。
怎么去压缩图片呢?官方给出了 image-webpack-loader,最好配合 url-loader 或 file-loader一块儿使用
这时能够在命令窗口看到,本来18k的图片被压缩很小的图片被打包进项目
注意: loader处理方式是从右到左,从下到上的,好比(老规则)

先调用postcss-loader 而后 css-loader 而后 style-loader
最后老规矩,欢迎点赞和纠错,祝你们工做愉快!