认识webpack
webpcak是基于JS应用的前端模块化打包工具,强调模块化(核心)和打包。
流行打包工具:webpack,grunt,gulp
前端模块化规范方案:AMD, CMD, CommonJS(node), ES6(不需要底层支撑,可以直接用)
前端模块化概念:
在ES6之前,我们如果想进行模块化开发,必须借助于其他工具进行模块化开发,在我们完成项目后,还需处理模块间的依赖关系,最终进行整合打包。
而webpack的出现,使这些问题迎刃而解,webpack的核心是让我们尽可能的进行模块化开发,与此同时,还会帮助我们处理模块间的依赖关系。
此外,webpack不仅限于对.js文件的模块化,例如css,png,jpg,json等在webpack中都可以当做模块来使用。
打包的概念:理解了webpack可以帮助我们进行模块化开发,并且能够处理模块间的各种复杂关系,打包的概念就很容易理解了。
打包,就是将webpack中的各种资源模块进行打包合并成一个或者多个包(Bundle)
于此同时,在打包过程当中,webpack还会对资源进行处理,例如一些压缩图片的操作等,将scss转成浏览器能识别的css,将ES6相关语法转成目前浏览器高度普遍支持的ES5语法,将TypeScript转成JS等等操作。
webpack的安装
首先我们得明确一点,webpack能够正常运行必须依赖Node环境来实现。
与此同时,node环境为了可以正常执行各种各样的的代码语言,其中必须必须包含各种依赖的包,也就是常说的npm工具(node packages manger)。
为了方便理解,我们可以把npm工具看成手机上的应用商店,你想下载什么软件,就直接去找,然后点击下载,npm工具使用的原理也是如此大同小异,只需要相关的指令加上对应的包名即可下载到本地项目文件夹。
安装操作
安装webpack之前首先需要安装node.js,因为node.js自带了软件包管理工具npm
查看自己的node版本号和npm版本号:
node -v
npm -v
全局安装webpck(版本号:3.6.0,vue cli2稳定支持版本)
npm i [email protected] -g
语法糖解释:
i选项是install的缩写(安装的意思)
-g 全局安装(global的缩写)
@后跟版本号
局部安装webpack
cd 进入相对于的目录
npm i [email protected] --save-dev
关于--save-dev的解释:它是开发时依赖,项目打包完成后,不需要继续使用。
查看webpack版本号:
webpack --version
webpack全局安装和局部安装的区别:
选择全局安装可以在任何一款流行的代码编译工具的终端打开,包括cmd窗口打开,这些都是全局安装的。
webpack的起步及基本使用体验。
新建2个基本目录结构:
我们要做的就是通过webpack工具将src下面的代码打包放入dist进行发布。
我们开发代码一般在源码目录下进行。
首先在根目录新建一个index.html,有一个基本骨架即可,切记切记不需要写外部引入.js文件,因为我们使用commonjs和ES6规范写的,浏览器是不认识。
在src目录下新建一个main.js文件作为程序的主要入口文件。
1.使用CommonJS模块化规范演示写代码,然后用webpack工具打包。
math.js文件作为导出口,main.js作为导入口。
打开VSC终端,将入口文件main.js进行打包,而math.js是作为导出口,是不需要我们进行同样的操作的,因为webpack会自动帮我们处理main.js所依赖关系的文件和包。
关于在VSC里面检测不到版本号和打包报错,看这篇:
https://www.jianshu.com/p/34470e43503b
通过上述wenbpack指令打包完成后,我们可以看到dist目录下多了一个bundle.js文件。
有了这个bundle.js文件后,我们就可以在Index.html里面用script标签外部引入了。
控制台查看我们CommonJS模块导出导入有没有成功。
2.下面在src目录下新建一个info.js脚本文件,使用ES6模块化规范思想。
再次运行webpack指令。
我们可以看到ES6模块化的控制台输出了。
webpack的配置
上面的webpack都是手动打包代码,每次写代码,都要输入一行长长的命令进行更新,如何做到智能打包呢?只要简单输入一个webpack就可以打包了,这就涉及到webpack配置了。
新建一个webpack.config.js文件,命名固定。
到这一步,打开VSC的终端,输入npm init
将原来webpack目录下写好的文件统统复制一份放到webpack配置目录下。
打开终端,直接输入webpack,不再需要敲长长的路径指令。
打包成功。
总结:将出口文件和入口文件放进配置文件,就可以直接使用webpack进行打包,更方便了。
将webpack.config.js映射到npm run当中去
找到并打开我们刚刚加进来的package.json文件,找到脚本所在行。
手动添加build脚本,完成映射,这样我们就可以敲npm run build指令了。
(学习了vue-cli后,我们会看到有npm run start /npm run server / npm run dev等等映射指令,都是经过webpack进行打包映射的。)
我们把dist下面的bundle.js文件删掉测试下刚刚配置好的映射npm run bulid指令。
我们发现bundle.js文件又被恢复了,证明我们映射的npm run build是成功了的。
webpack全局安装和局部安装的问题
我们现看下自己的现在全局安装的webpack版本号,发现是4.44.1的版本了。
而我们手头上的项目当时用的webpack的3.6.0的版本进行配置的,依赖的也是3.6.0的版本。
用4.44.1的webpack版本去配置3.6.0的webpack版本会报错。
这时候就要在本地安装依赖了,在本地安装一个webpack3.6.0的版本。
--save-dev的解释:开发时依赖,在项目开发的时候要用到webpack,项目开发完成打包上传到服务器后,项目运行起来就不在需要webpack了。(还有一个叫运行时依赖的)
安装完成后,我们重新打开package.json文件进行查看,发现多出了一个名叫devDependencies的代码行。
与此同时,我们发现文件夹下多出一个node_modules的文件夹。
打开它,我们能找到webpack依赖的相关信息文件。
只要是在终端敲webpack都是全局安装的,webpcak本地(局部)安装的是在package.json里面的脚本行配置,npm run build默认是找局部的,本地找不到,才会找全局。
总结:1.出入口文件的配置,2.weback局部安装的配置。
loader的使用
loader是webpack中一个非常核心的概念。
webpack可以用来做什么?
通过上面的例子,我们发现我们主要用webpack来处理我们写的js规范代码,并且webpack会帮助我们自动处理JS之间的相关依赖。
但是,在实际开发中,我们不仅仅只有基本的JS代码的处理,我们有时候也要加载CSS,图片,ES6转ES5,TypeScript转ES5,scss,sass还有less转css,.jsx文件和.vue文件转js文件等等。
对于webpack本身的能力来说,这些转化是不支持的,怎么办?
这时候呢,需要给webpack拓展对应的loader。
loader使用过程:
步骤一:通过npm安装需要的loader
步骤二:在webpack.config.js中的module关键字进行配置。
接下来进入代码视图(以打包CSS为例子作为index.html的引用)
首先我们整理下文件夹,在src目录下新建一个名叫JS文件夹放置.js脚本代码文件,将原先其他的.js文件拖拽进去放置,只要把main.js裸露出来就好。
在src目录下新建一个名叫CSS的文件夹,用于放置.css文件,在CSS目录下,创建一个nomal.css文件,写入简单的样式用于测试。
在main.js入口文件做css包的依赖。
然后打开终端,输入npm run build,我们发现报错了。
我们打开webpack中文官方网站提供的文档:
https://www.webpackjs.com/loaders/#%E6%A0%B7%E5%BC%8F
找到它,点击超链接进去看解决方案。
首先打开终端安装
安装完成后,打开webpack.config.js进行相关配置。
配置好后,终端再次运行npm run build,我们发现又报错了。
原因是当前版本太高了,需要降低版本(使用2.0.2版本)。
终端再次测试npm run build 报错解除。
配置和安装完css-loader后,我们还需要在webpack.config.js里面配置style-loader和在终端安装style-loader,不然是样式没有生效的。
再次执行npm run build
我们看下刚刚index.html的效果,打包的是normal.css文件。
上面学了js,css文件的打包处理,下面演示less文件处理
在CSS目录下,创建一个special.less文件
来到入口文件main.js做less的依赖。
终端输入npm run built ,不出意外的话还是会报错。
同上面css的解决方案,已经有经验了,打开webpack官网
https://www.webpackjs.com/loaders/#%E6%A0%B7%E5%BC%8F
找到less相关的资料,点击超链接,看解决方案。
安装less-loader
在webpack.config.js配置less-loader
终端运行npm run build,版本太高了,报错了。
指定版本号安装。
安装完成后再次执行,npm run build
报错解除。
来到main.js文件给页面添加文字。
再次运行npm run build
看下页面效果,less语法的样式生效了。
打包图片处理
在src目录下新建一个名叫img的文件夹,顺带放置进去2张图片。
打开CSS目录下的normal.css样式文件,将图片作为页面的背景。
如果终端直接执行npm run build的话,肯定会报错,报错提示我们去安装合适的loader,同上面遇到的情况一样。
所以我们去官网看教程,点击蓝色字体的超链接,看解决方案。
安装url-loader:
npm install --save-dev url-loader
报错的话,一般和版本号有关,所以指定版本号很重要。
npm i --save-dev [email protected]
打开webpack.config.js进行配置。
拓展:早期DOS操作系统只支持后缀3位,常见的.htm和.jpg文件格式,到了window操作系统,才有了.html和jpeg格式(支持后缀4位),区别不大。
当我们运行npm run build 的时候报错了,提示我们没有找到'file-loader',这是因为webpack.config.js文件的file-loader的limit参数的限制问题。
limit参数限制是个致命的玩意,如果不留意,非常容易报错,出现上面报错的,解决方案看这篇。
https://www.jianshu.com/p/b26b252dc78c
报错解除后,我们看到了index.html的页面(刚刚写在normal.css的背景图片url样式)。
查看body的样式,为什么这里有个base64?
这跟我们设置webpack.config.js文件的url-loader下的limit参数有关。
当加载图片大于limit时,需要安装file-loader,否则打包报错。
使用file-loader在这篇:https://www.jianshu.com/p/b26b252dc78c
ES6语法处理
如果ES6语法没有转成ES5,那么意味着可能一些对ES6还不支持的浏览器没有办法很好的运行我们的项目代码。
我们可以看下dist目录下的bundle.js文件的ES6语法。
如果希望我们的ES6语法转成ES5,那么就需要babel。
所以我们需要安装babel对应的loader.
官网教程:https://www.webpackjs.com/loaders/babel-loader/
我们安装的跟官网的参数有点不一样。
npm i -S -D babel-loader@7 babel-core babel-preset-es2015
语法糖解释:
-S 是--save的缩写
-D 是-dev
--save-dev 的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖。
devDependencies 中记录的是项目在开发过程中需要使用的一些文件,
在项目最终运行时是不需要的也就是说我们开发完成后,最终的项目中是不需要这些文件的。
配置webpack.config.js文件
我们只需要复制官网的这一部份,修改下参数,放到我们的webpack.config.js文件即可。
终端执行 npm run build 重新打包,查看bundle.js文件,发现其中的内容变成了ES5语法(const变成var了)
webpack中配置Vue
使用Vuejs进行开发,是以特殊的文件来组织vue的组件的,所以我们要学习如何在webpack环境中集成Vuejs
因为我们后续的实际项目也会使用vue,所以并不是开发时依赖,去掉-dev参数.
npm i vue -S
语法糖:--save简写-S
安装成功后显示:
打开main.js入口文件做vue的依赖。
来到index.html文件做vue实例的挂载。
重新npm run build打包,看下页面效果,其实页面效果并没有出来,还直接报错了。
这是因为vue在构建最终的版本时,构建了2类版本
所以我们要使用的是runtime-compiler版本,打开webpack.config.js文件进行配置,使用alias别名的方式指定runtime-compiler版本。
终端运行npm run build 重新打包
报错解除,效果出来了。
template和el的关系,在vue实例里面同时写了template和el,template会将el给替换掉
SPA:单页面应用(simple page web application)--用前端路由跳转vue-router
在main.js的vue实例里写入vue代码。
运行npm run build看下效果,发现页面是被替换了,显示的是template的内容,所以验证了template会替换掉el,提醒我们不要在挂载点(绑定的el:"#app")里面写入任何vue代码。
但这样写的template显然是不合适,我们需要将其抽成一个组件
我们npm run build看下效果
效果可以实现了,但是这样的代码还是不好,因为我们的组件的是个对象,它还可以抽离成单个文件。
在src目录下创建一个名叫vue的目录,创建一个app.js文件。
我们npm run build看下效果
但这样的代码还是不好的,因为vue的模板template和vue脚本没有做到分离
所以我们还可以抽离,在vue目录下创建App.vue文件。
我们将app.js代码抽离成App.vue
执行npm run build,但我们会发现报错了。
报错提示我们去配置对应的loader
注释:vue-template-compiler是编译模板的意思,安装的是开发时依赖。
安装完成后,来到webpack.config.js进行vue-loader的相关配置。
注释:/正则表达(匹配所有.vue结尾的文件)/
执行npm run build,继续报错了。
报错提示我们缺失了一个plugin(插件)
这是因为vue-loader版本太高的原因导致的,v14开头的版本号往上都要安装插件了。
我们可以找到package.json文件,查看下当前项目当中的vue-loader版本号,已经是15.9.3的版本了。
所以我们要做到是降低版本号,手动修改成v14版本以下的版本号。
在package.json中手动修改版本号后,要在终端要重新运行安装依赖
npm i
安装完成依赖后,继续npm run build,到这里,所有的报错都解除了
降低版本号,是其中一种解除报错的方法,另外一种是去官网装插件。
最后抽成了组件化开发的思想,实现2个.vue文件的父子组件嵌套
在vue目录下创建一个HelloWorld.vue文件
执行npm run build进行编译
小结:组件化开发最终形成组件树。
拓展:配置.vue后缀省略的操作(类似还又.css,.js等后缀文件)‘
我们原来的文件都是带后缀的(下图),这是因为没有做后缀的相关的配置。
如果我们想省略后缀的话,打开webpack.config.js文件,找到resolve对象。
配置extensions
参数注释:
resolve对象 一般用于解决路径问题。
extensions参数 解决拓展名的问题
这里的.vue后缀就可以去掉了。
最后npm run build 进行编译,可以看到效果,如果没有配置extensions参数,直接省略了文件后缀名是会报错的。
总结:从基础的一步一步抽离的话,我们不知不觉间已经接近了vue的脚手架了的.vue文件,整个框架也稍微清晰了。(整个生态)
plugin插件的使用
1.什么plugin?
plugin中文是插件的意思,通常是用于对某个现有框架进行拓展,插件的出现是为了优化框架和拓展框架的功能而衍生出来的。
举个栗子,webpac中的插件,就是对webpack现有功能的各种拓展,比如打包优化,文件压缩等待。
2.loader和plugin的区别:
loader主要用于转换某些类型的模块,确切的说,它是一个转换器又是一个加载器,使用其他的模块或文件时需要加载相应的loader。
plugin是插件,它是对webpack本身功能的拓展,相当于一个拓展器。
3.plugin的使用过程
步骤一:通过npm安装需要使用到的plugins(某些webpack已经自带内置的插件是不需要安装的)
步骤二:在webpack.config.js中的plugins参数中配置插件。
(1)添加版权声明插件,BannerPlugin(横幅插件),这个插件的作用就是些类似上面截图的版权声明。
打开webpack.config.js文件通过CommonJS语法require导入webpack模块,然后增加plugins参数,通过new webpack实例来使用。
运行npm run build进行编译,编译完成后,找到dist目录下的bundle.js文件进行打开,我们看到版权声明已经添加进来了。
(2)打包html的插件,HtmlWebpackPlugin插件
为什么需要打包html的插件?
因为项目开发完成后,我们需要真实发布项目,我们是把整个dist目录上传到服务器的,发布的是dist文件中的内容,但是dist目录下并没有index.html这个文件,那么打包的js文件就没有意义了,因为我们的index.html在src源码根目录下放置着。
所以,我们需要将src源码根目录下的index.html文件打包到dist文件夹中,这个时候就用到了HtmlWebpackPlugin插件
HtmlWebpackPlugin插件可以帮助我们实现的功能:
- 在dist目录下自动生成一个index.html文件(可以指定模板来生成)
- 将打包的js文件,自动通过script标签插入到body中
安装HtmlWebpackPlugin插件
npm i html-webpack-plugin -S -D
使用插件,修改webpack.config.js文件中的plugis部分内容如下:
- 通过require引入html-webpack-plugin模块
-
在plugins参数中配置new HtmlWebpackPluginl()来使用插件。
重新打包编译 运行npm run build
我们发现dist目录下多出了一个index.html文件。
我们打开dist目录下的index.html文件,有些要注意的部分。
-
注释掉pubilcPath默认的dist路径
-
添加实例挂载点
首先来到src目录下的index.html文件,删掉脚本行引入,只需要保留挂载的即可。
因为我们dist目录下的index.html文件是根据src目录下的index.html文件的模板生成的。
修改webpack.config.js文件中的plugis部分,找到new HtmlWebpackPluginl(),配置template参数,内容如下:
接下来我们需要验证效果,所以要将dist目录下的所有文件全部删除(保留一个空的dist文件夹即可)。
运行npm run build 进行编译
我们发现了刚刚删除的所有文件都自动生成新的(恢复了)。
打开dist目录下的index.html文件。
(3)JS脚本的压缩插件
为什么需要压缩脚本文件?
在项目发布只之前,尽量要压低文件大小,这和用户体验有关,我们日常也在应用商店下载软件app,都会留意以下软件的大小,有些app只有几十M不到,有些过百M的,那当然是几十M的下载更快一些,所以我们要对js文件进行压缩处理.
我们使用的是第三方插件 uglifyjs-webpack-plugin
uglify是丑化的意思,它的实际效果就是将js文件下的空格字符给删除掉(因为我们的代码编写规范习惯都是层层缩进的,导致了出现了很多很多的空格,空格看起来好像什么,但空格也是字符,占用字节大小的),几千空格字符累计起来,它的字节可不小,此外,JS中定义的一些变量名也会用其他字符进行转译,注释也会被删掉。这样就达到了整体的压缩效果。
安装第三方插件 uglifyjs-webpack-plugin,指定版本号1.1.1和cli2保持一致
npm i [email protected] -S -D
在webpack.config.js文件中通过require引入使用插件。
修改webpack.config.js文件中的plugis部分内容如下:
运行npm run build 编译
我们打开dist目录下的bundle.js查看压缩后的丑化效果。
我们看到了密密麻麻难以看懂的代码,这就是这个第三方插件的效果,丑是丑了点,但实现了文件的压缩。
搭建本地务器(涉及node知识)
为什么要搭建本地服务器?需求是什么?
搭建本地服务器可以实现浏览器页面自动刷新的功能,也就是达到实时加载的效果.
本地服务器搭建好后,会提供给我们一个服务器的端口号,这个就好像vue-cli提供的8080服务器端口号。
有了它,不再需要去手动点击刷新了页面了(我们以前写的代码都是手动刷新的,只能说,编写单个html文件的时候还好)
换到项目中,你要不停的运行npm run build 这条编译指令(上面一步步走来,我们已经体验过了,实在是繁琐),这样的开发效率实在太慢了,一个简单浏览器的页面刷新,就能把人折腾够呛。
当然了,现在有些代码编译器安装某些插件也可以实现单页面的实时加载了,例如VSC的LIve Server插件。
基于node.js搭建本地服务器
- webpack提供了一个可选的本地开发服务器,这个本地服务器是基于node.js进行搭建的,它的内部采用的是express框架,可以是实现浏览器实时加载刷新的效果。(也是就是让浏览器自动刷新显示我们修改后的代码效果)
webpack-dev-server是webpack的一个单独模块,使用之前需要安装
npm i -S -D webpack-dev-server
指定版本号安装:
npm i -S -D [email protected](相当于vue2脚手架的版本,还对应webpack3.6.0的版本)
devserver是webpack的一个选项,它可以设置如下属性:
- contentBase: 为哪一个文件夹提供本地服务,默认是根文件夹,这里要填写./dist
- port: 是端口号
- inline: 页面实时刷新,填写的是布尔值
- historyApiFallback: 在SPA页面中,依赖HTML5的history模式
webpack.config.js文件配置修改如下:
package.json文件做添加脚本指令映射,如下
现在我们运行 npm run dev,因为在webpack.config.js中没有指定port,默认的是本地8080端口.
我们可以复制网址去打开看看效果,这样本地服务器就被搭建起来了。
修改下我们项目的代码,发现我们浏览器自动刷新的效果也起来了,不再需要手动点击刷新。
细节补充:
但这样我们还是要手动点击8080端口的链接打开,这里我们还可以在package.json中配置一个--open的参数,或者在webpack.config.js中devServer添加属性open: true来达到自动打开8080端口(二选一)
--open参数就是在我们运行npm run dev的时候,浏览器自动帮助我们打开本地8080服务器端口,不再需要复制链接去打开。
webpack配置文件的抽离
因为有些配置是我们开发的时候要用到的配置,到了发布的时候有些配置并不需要了,比如我们的本地服务器搭建,我们之所以要搭建本地服务器是为了提高我们的代码开发测试效率,项目完成发布后,这个搭建好本地服务器是不再需要的了,所以要做到将其抽离出去,做成单个js文件。
所以,我们要实现的就是开发时的配置和发布时的配置分别放置。
在当前项目下,创建一个build目录,放置三份脚本配置文件,将webpack.config.js一分为三,各自实现自己该有的配置(如右图所示)。
一分为三后的各自配置。
base.config.js
//公共配置
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.css$/,//正则表达式
use: ['style-loader', 'css-loader']
},
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8196,
name: 'img/[name].[hash:8].[ext]'
}
}
]
},
{
test: /\.js$/,//匹配JS文件
exclude: /(node_modules|bower_components)/,//只需转化src目录下的代码,其他文件夹的排除在外
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
},
{
test: /\.vue$/,
use: ['vue-loader']
}
]
},
resolve: {
extensions: ['.css', '.js', '.vue'],
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins: [
new webpack.BannerPlugin('最终版权归qinfubin所有'),
new HtmlWebpackPlugin({
template: 'index.html'
}),
]
}
最终编译发布的时候,需要的是,base.config.js和production.config.js
开发中需要的是,base.config.js和dev.config.js
我们最终要发布上传到服务器,所以现在我们要对base.config.js和production.config.js配置文件进行合并,dev.config.js是我们开发的时候要用到,项目完成后不需要了。
安装webpack-merge
npm i webpack-merge -S -D
带版本号的:
npm i [email protected] -S -D
注释:merge就是合并的意思
安装完webpack-merge后,production.config.js配置文件的配置如下:
dev.config.js配置文件的配置如下:
将webpack.config.js一分为三并且配置合并后,它也没必要存在了,可以进行删除。
接下来,手动配置package.json的脚本映射,因为我们的路径变了,要指向到build目录下。
接下来,修改base.config.js配置文件的path参数下dist路径指向(因为这个路径指向不更改的话,npm run build之后默认打包到build目录下了,而我们要打包到的是dist目录下)
最后执行2次编译
npm run build
npm run dev
出现这个就算完成了一分为三的配置抽离任务了.