
一、webpack-webpack起步
一、前端发展的阶段
到Web前端的发展是非常快速的,对于开发者来说我们会更加深有体会
- 从后端渲染的JSP、PHP,到前端原生JavaScript,再到jQuery开发,再到目前的三大框架Vue、React、Angular;
- 开发方式也从原来的JavaScript的ES5语法,到ES6、7、8、9、10,到TypeScript,包括编写CSS的预处理器less、scss等;
二、前端开发的复杂化
开发过程中我们需要通过模块化的方式来开发;
- 比如也会使用一些高级的特性来加快我们的开发效率或者安全性,比如通过ES6+、TypeScript开发脚本逻辑, 通过sass、less等方式来编写css样式代码;
- 比如开发过程中,我们还希望试试的监听文件的变化来并且反映到浏览器上,提高开发的效率;
- 比如开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化;
- Vue-CLI、create-react-app、Angular-CLI都是基于webpack来帮助我们支持模块化、less、TypeScript、打包优化等的;
三、webpack是什么
webpack是一个静态的模块化打包工具,为现代的JavaScript应用程序;
我们来对上面的解释进行拆解:
- 打包bundler:webpack可以将帮助我们进行打包,所以它是一个打包工具
- 静态的static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器);
- 模块化module:webpack默认支持各种模块化开发,ES Module、CommonJS、AMD等;
- 现代的modern:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了webpack的出现和发展;
日常工作来说,比如在开发vue、react、 angular等项目的过程中我们需要一些特殊的配置:
- 比如给某些目录结构起别名
- 让我们的项目支持sass、less等预处理器
- 希望在项目中手动的添加 TypeScript的支持
- 都需要对webpack 进行一些特殊的配置工作。
在原有的脚手架上来定制一些自己的特殊配置提供性能:
- 比如安装性能分析工具、
- 使用gzip压缩代码、引用cdn的资源,公共代码抽取等等操作
- 甚至包括需要编写属于自己的loader和plugin。
对于想要在前端领域进阶成为高级前端开发工程师来说:
- webpack等构建工具是必须学习的, 包括其中的一些高级特性和原理,都是要熟练掌握的。
- 企业在招聘高级前端工程师 或者架构师时,必然会对webpack和其他 的构建工具有比较高的要求。
四、webpack的安装
webpack的安装目前分为两个:webpack、webpack-cli
那么它们是什么关系呢?
- 执行webpack命令,会执行node_modules下的.bin目录下的webpack;
- webpack在执行时是依赖webpack-cli的,如果没有安装就会报错;
- 而webpack-cli中代码执行时,才是真正利用webpack进行编译和打包的过程;
- 所以在安装webpack时,我们需要同时安装webpack-cli(第三方的脚手架事实上是没有使用webpack-cli的,而是类似于 自己的vue-service-cli的东西)
1 | npm install webpack webpack-cli –g # 全局安装 |
五、传统开发的问题
传统开发我们的代码存在什么问题呢?某些语法浏览器是不认识的(尤其在低版本浏览器上)
- 使用了ES6的语法,比如const、箭头函数等语法;
- 使用了ES6中的模块化语法;
- 使用CommonJS的模块化语法;
- 在通过script标签引入时,必须添加上 type=”module” 属性;
上面存在的问题,让我们在发布静态资源时,是不能直接发布的,因为运行在用户浏览器必然会存在各种各样的兼容性问题。
我们需要通过某个工具对其进行打包,让其转换成浏览器可以直接识别的语法;
比如此时我新建文件如下:
index.js:
1 | import { message } from './math.js'; |
math.js
1 | function sum(n1, n2) { |
index.html
1 |
|
此时浏览器报错:
因为浏览器不认识CommonJS的语法,无法进行解析编译。
这就是传统开发不借用打包工具存在的问题。
六、webpack默认打包
可以通过webpack进行打包,之后运行打包之后的代码
在目录下直接执行 webpack 命令
1 | E:\project\vs project\webpack\01_webpack初体验>webpack |
注意此时的webpack是全局下的webpack,局部我还没有安装
打包后会 生成一个dist文件夹,里面存放一个main.js的文件,就是我们打包之后的文件:
dist -> main.js:
1 | (()=>{"use strict";var e,r={52:(e,r,o)=>{o.r(r),o.d(r,{message:()=>t}),e=o.hmd(e);const t="Hello";e.exports={sum:function(e,r){return e+r}}}},o={};function t(e){var n=o[e];if(void 0!==n)return n.exports;var s=o[e]={id:e,loaded:!1,exports:{}};return r[e](s,s.exports,t),s.loaded=!0,s.exports}t.d=(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},t.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:()=>{throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),t.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},e=t(52),console.log(e.message),t(52)(1,2)})(); |
这个文件中的代码被压缩和丑化了; 暂时不关心他是如何做到的,后续讲webpack实现模块化原理时会再次讲到;
另外发现代码中依然存在ES6的语法,比如箭头函数、const等,这是因为默认情况下webpack并不清楚我们打包后的文件是否需要转成ES5之前的语法,后续需要通过babel来进行转换和设置;
我们发现是可以正常进行打包的,但是有一个问题,webpack是如何确定我们的入口的呢?
- 事实上,当我们运行webpack时,webpack会查找当前目录下的 src/index.js作为入口;
- 所以,如果当前项目中没有存在src/index.js文件,那么会报错;
七、本地安装webpack
我们不能一直使用全局下的webpack
因为我们使用全局webpack的版本可能很高,比如v5,而别人本地的webpack版本是v3
那么别人再拉取到项目并执行打包命令时,就可能会引发很多问题
所以我们需要再本地也就是局部安装webpack,webpack-cli,这样就可以在package.json中进行记录
在别人拉取项目时,执行npm install,就会安装和我们一样的版本的webpack,避免了很多问题
首先npm init生成package.json文件
npm init
1 | { |
本地安装webpack webpack-cli
1 | npm install webpack webpack-cli –D |
注意:安装以后执行webpack也会去执行全局下的webpack
解决办法:
- npx webpack 这就会去局部的node_modules下的bin目录下去寻找webpack打包文件
- 在package.json中配置脚本
1 | "scripts": { |
这样执行npm run build,就会默认去局部node_modules下的bin目录下的webpack进行打包
八、webpack配置文件
- 前面提到当我们运行webpack时,webpack会查找当前目录下的 src/index.js作为入口;
- 所以,如果当前项目中没有存在src/index.js文件,那么会报错;
修改入口出口文件配置
1 | npx webpack --entry ./src/main.js --output-path ./build |
指定入口文件为src目录下main.js
指定出口文件为 ./build文件夹
可以放到脚本里来简化
1 | "scripts": { |
更多相关API可以参考官网document文档。
webpack.config.js
不能一直在命令行里写相关命令
应该新建webpack.confin.js文件进行统一配置
webpack在进行打包时会看目录下是否含有webpack.config.js这个文件
- 有的话会按照这个文件里的配置进行打包
- 没有的话就按照默认的配置打包
1 | const path = require('path'); |
webpack.config.js改名
如果我们的配置文件并不是webpack.config.js的名字,而是其他的名字呢?
比如我们将webpack.config.js修改成了 wk.config.js;
这个时候我们可以通过 –config 来指定对应的配置文件;
1 | webpack --config wk.config.js |
但是每次这样执行命令来对源码进行编译,会非常繁琐
所以我们可以在package.json中增加一个新的脚本:
1 | "scripts": { |
之后我们执行 npm run build来打包即可 。
九、webpack依赖图
webpack到底是如何对我们的项目进行打包的呢?
- 事实上webpack在处理应用程序时,它会根据命令或者配置文件找到入口文件
- 从入口开始,会生成一个 依赖关系图,这个依赖关系图会包含应用程序中所需的所有模块(比如.js文件、css文件、图片、 字体等);
- 然后遍历图结构,打包一个个模块(根据文件的不同使用不同的loader来解析)