webpack总结
原理
- 代码转换:
typeScript
编译成JavaScript
、scss,less
编译成css
- 文件优化:压缩
JavaScript
、html
、css
文件,压缩合并图片等 - 代码分割:提供多个页面的公共代码,抽离首屏不需要的代码使其异步加载
- 模块合并:模块化的项目里会有很多模块和文件,构建狗能把模块分类合并
- 自动刷新:监听本地源代码,自动重构刷新浏览器
- 扩展性好,插件机制完善
打包过程
- 利用babel完成代码转换,生成单个文件依赖
- 从入口开始分析,生成依赖图谱
- 将引用模块打包为立即执行函数
- 把最终的bundle文件写入bundle.js里
四大核心
- entry:入口,即js入口源文件
- output:生成文件
- loader:文件处理
- plugins:插件
Entry
webpack应该用哪个模块作为入口文件,作为构建内部依赖图的开始,进入入口后,webpack会找到哪些库和模块是入口依赖的,并随即被处理,最后输出到bundle.js的文件中
1 |
|
Output
告诉webpack在哪输出bundles,以及怎么命名他,在配置文件中均可搞定
1 |
|
Loader
loader
让webpack能够处理非javaScript
文件,因为webpack自己只能看懂javaScript
。loader
能够把所有类型的文件转换成webpack能够处理的模块,然后利用打包能力对他进行处理
Loader的特点
- 每一个loader的职责都是单一的,只能完成一种转换
- loader本质上是node.js模块,这个模块需要导出一个函数
- loader总是从右到左被调用
常用Loader
处理样式
css-loader
加载css文件style-loader
使用style标签把css-loader
内部样式注入到html中less-loader,sass-loader
解析css预处理器
处理js
让我们能够使用最新的js代码(ES6,ES7等)及让我们能够使用基于js进行了拓展的语言,比如JSX等
处理文件
通常使用的两种loader是file-loader
和url-loader
,两者主要的区别是url-loader
能够设置图片的大小限制,如果大小超过限制,则行为等同于file-loader
,如果图片大小不超过限制,那么图片会以base64的形式打包
处理vue单文件
vue-loader
是webpack的加载器魔铠,它让我们的随心所欲的编写.vue
格式的单文件组件。vue-loader
模块允许 webpack
使用单独的加载器模块(例如 sass 或 scss 加载器
)提取和处理每个部分。该设置使我们可以使用 .vue
文件无缝编写程序。
在文章最后,我们会尝试开发一个简易的loader来加深我们的理解
Plugin
专注于处理webpack在编译过程里某个特定任务的功能模块
特点
是一个独立的模块
模块对外暴露一个js函数
函数的原型
(prototype)
上定义了一个注入compiler
对象的apply
方法apply
函数中需要有通过compiler
对象挂载的webpack
事件钩子,钩子的回调中能拿到当前编译的compilation
对象,如果是异步编译插件的话可以拿到回调callback
完成自定义自编程流程并处理
complition
对象的内部数据如果异步编译插件的话,数据处理完成后执行
callback
回调
常用Plugin
HotModuleReplacementPlugin
代码热替换。因为Hot-Module-Replacement
的热更新是依赖于webpack-dev-server
,后者是在打包文件改变时更新打包文件或者 reload 刷新整个页面,HRM
是只更新修改的部分。HtmlWebpackPlugin
, 生成 html 文件。将 webpack 中entry
配置的相关入口 chunk 和extract-text-webpack-plugin
抽取的 css 样式 插入到该插件提供的template
或者templateContent
配置项指定的内容基础上生成一个 html 文件,具体插入方式是将样式link
插入到head
元素中,script
插入到head
或者body
中。ExtractTextPlugin
, 将 css 成生文件,而非内联 。该插件的主要是为了抽离 css 样式,防止将样式打包在 js 中引起页面样式加载错乱的现象。NoErrorsPlugin
报错但不退出 webpack 进程UglifyJsPlugin
,代码丑化,开发过程中不建议打开。uglifyJsPlugin
用来对 js 文件进行压缩,从而减小 js 文件的大小,加速 load 速度。uglifyJsPlugin
会拖慢 webpack 的编译速度,所有建议在开发简单将其关闭,部署的时候再将其打开。多个 html 共用一个 js 文件(chunk),可用CommonsChunkPlugin
purifycss-webpack
。打包编译时,可剔除页面和 js 中未被使用的 css,这样使用第三方的类库时,只加载被使用的类,大大减小 css 体积optimize-css-assets-webpack-plugin
压缩 css,优化 css 结构,利于网页加载和渲染webpack-parallel-uglify-plugin
可以并行运行 UglifyJS 插件,这可以有效减少构建时间
同样的,文章最后我们也会尝试开发一个Plugin
webpack配置
1、Webpack 项目初始化
1、新建 Web 项目
新建一个目录,再进入项目根目录执行 npm init 来初始化最简单的采用了模块化开发的项目;最终生成 package.json 文件;
1 |
|
2、安装 Webpack 到本项目
(1)查看 Webpack 版本
运行以下命令可以查看 Webpack 的版本号
1 |
|
(2)安装 Webpack
可以选择(1)步骤罗列得到的 Webpack 版本号,也可以安装最新稳定版、最新体验版本,相关命令如下所示,我选择安装 4.28.2 版本(没有为什么,就想装个 4.x 的版本);
1 |
|
(3)安装 Webpack 脚手架
需要安装 Webpack 脚手架,才能在命令窗口执行 Webpack 命令,运行以下命令安装 Webpack 脚手架;
1 |
|
3、使用 Webpack
使用 Webpack 构建一个采用 CommonJS 模块化编写的项目;
(1)新建页面入口文件 index.html
1 |
|
(2)新建需要用到的 JS 文件
show.js 文件
1 |
|
main.js 文件
1 |
|
(3)新建 Webpack 配置文件 webpack.config.js
1 |
|
(4)执行 webpack 命令进行构建
在 package.json 文件中配置编译命令,如下所示:
1 |
|
执行以下命令进行项目的 Webpack 编译,成功后会在项目根目录下生成编译目录 dist ;
1 |
|
(5)运行 index.html
编译成功后,我们用浏览器打开 index.html 文件,能看到页面成功显示 “Hello Webpack”;
2、Loader 配置
本节通过为之前的例子添加样式,来尝试使用 Loader;
(1)新建样式文件 main.css
1 |
|
(2)将 main.css 文件引入入口文件 main.js 中,如下所示:
1 |
|
(3)Loader 配置
以上修改后去执行 Webpack 构建是会报错的,因为 Webpack 不原生支持解析 CSS 文件。要支持非 JavaScript 类型的文件,需要使用 Webpack 的 Loader 机制;
(3.1)运行以下命令,安装 style-loader 和 css-loader,其中:
- css-loader 用于读取 CSS 文件;
- style-loader 把 CSS 内容注入到 JavaScript 中;
1 |
|
(3.2)进行以下配置
1 |
|
(4)查看结果
编译后,刷新 index.html ,查看刚刚的样式 loader 已经起作用;
3、Plugin 配置
(1)安装样式提取插件 extract-text-webpack-plugin
1 |
|
(2)plugin 文件配置如下
1 |
|
(3)查看结果
通过以上配置后,执行 Webapack 的执行命令,发现在 dist 目录下,生成对应的 css 文件;存在的坑点:
- 我们需要手动将生成的 css 文件引入到 index.html 中;
- 修改 css 文件后,会生成新的 css 文件,原先的不会删除;
4、使用 DevServer
(1)执行以下命令安装 webpack-dev-server
1 |
|
在 package.json 中配置启动命令
1 |
|
运行命令后,就可以启动 HTTP 服务
1 |
|
启动结果如下所示,我们可以通过 http://localhost:8080/ 访问我们的 index.html 的demo
(2)实时预览
我们在运行命令后面添加参数 –watch 实现实时预览,配置如下所示:
1 |
|
然后我们修改 main.js 的传入参数,发现并不能实时预览,也没有报错!!! why?
踩坑:
在 index.html 中需要将 js 的路径修改为:
1 |
|
而不能是之前的(因为这个是编译生成的,并不是通过 devServer 生成放在内存的)
1 |
|
(3)模块热替换
可以通过配置 – hot 进行模块热替换;
番外
没错,文章最后了,现在我们开始开发一个loader
和plugin
开发一个loader
需求:开发一个loader
,将KobeBryant转换为
mamba forever`。
1.编写loader
新建目录my-loader
作为名字,执行npm init -y
快速创建一个模块化项目,然后新建index.js
1 |
|
2.注册模块
一般情况下,我们需要的loader都是利用npm安装,但是我们可以使用npm link
命令,以求在不发布模块的情况下,将本地的源码链接到项目的node_modules
下。在项目的根目录下执行以下命令
1 |
|
3.在webpack中配置loader
在webpack.base.config.js
中加上以下配置
1 |
|
这样我们js里所有的字符串KobeBryant
就会替换为mamba forever
了
4.配置参数
前面我们是写死的替换,如果我们想要通过配置项来进行改变怎么办
1 |
|
开发一个Plugin
- webpack在编译中,会广播很多事件
- webpack应用了观察者模式,插件可以监听webpack事件来触发对应的处理逻辑
- 插件中可以使用webpack的api
1.编写插件
创建目录my-plugin
作为编写的插件,执行npm init -y
快速创建一个模块化项目,然后新建index.js
1 |
|
2.注册模块
同样的,我们link一下,以便于我们能直接使用本地的模块
1 |
|
3.配置插件
在webpack.base.conf.js
加上以下配置
1 |
|