为什么用webpack这玩意儿?
大家有没有看过jquery框架的源码?知道它源码有多少行吗?
1.x版本的都在10000行以上。大家试想如果在开发时候这1万多行代码都在一个文件,那文件这么长,开发测试的时候会有多麻烦。于是乎有人就开始想了,开发的时候把代码按照不同的功能分成不同的文件,方便于开发调试,到发布的时候在把代码合并到一起就OK了,这个把代码合并到一起的玩意儿就是我们今天需要探讨的打包工具,也是它的最主要的功能之一:代码合并。
在我们前端开发中,大家一定还遇到过以下一些常见问题,诸如:
前端样式采用less或者scss开发,最新的es6语法,可是浏览器并不能识别(备注:可以引入转换脚本解决)
项目引入的css和js等文件太多,文件体积太大,势必会引起浏览器多次请求服务器加载资源引起速度慢,能不能减少文件数量和文件体积呢?
这就是今天的主角webpack要做的事情,看下去你就会知道如何使用!
webpack安装和入门案例
先来看看安装:
//初始化安装目录
npm init -y
安装webpack和webpack-cli(4.x以上版本需要安装webpack-cli)
npm install --save-dev webpack
npm install --save-dev webpack-cli
第一个案例总体目录如图所示:
第一步:建立src文件,在src文件下新建文件取名为index.js
//index.js内容如下
console.log("hello webpack");
第二步:使用webpack打包上面的文件
npx webpack
自此变自动生成了如图所示的dist目录和打包后的main.js文件
第三步:验证打包后的main.js文件是否正确
方法一:用html文件测试,我们的例子是会在控制台输出"hello webpack"字符串
webpack
方式二:因为我们这里只用到了js代码,可以进入到打包后的文件夹,用node来运行代码
node main.js
编译后的文件默认是生产环境,代码经过压缩所以直接看不懂,如果你希望能看懂编译后的js文件,或者你希望修改一下编译后的文件名称等,可以通过给webpack提供配置文件的方式来解决:
webpack配置文件
第一步:在项目目录下建立文件webpack.config.js
文件内容如下
let path = require('path'); //webpack是node写出来的,path是node的语法
module.exports = {
mode:'development', //编译环境改成是development(开发模式)
entry:'./src/index.js', //需要编译的源文件目录
output:{ //编译后的目录
filename:'configTest.js', //编译后的文件名称
path:path.resolve(\_\_dirname,'build') //编译后的路径,必须是绝对路径
}
}
第二步:编译打包文件和测试生成的文件方式和上一步相同,不过注意生成的文件名称变了
npx webpack //和之前的编译方式一样
配置文件名称能不能改?我公司的项目在打包编译的时候用的是npm run build是怎么回事?
比如我现在将webpack配置文件名改成了webpack.configOther.js,那么我在运行的时候可以通过指定配置文件名称的方式运行,如下:
npx webpack --config webpack.configOther.js
但是上述运行代码的方式明显太长,看着很不舒服,只需一步就可以搞定:
//打开package.json文件,添加如下key-value值
"scripts": {
"build": "webpack --config webpack.configOther.js"
},
接下来我们就可以通过npm run build的方式来编译我们的代码了。写在package.json文件scripts里的内容可以通过npm run 脚本名的方式来调用。
webpack开发环境搭建
上面我们测试自己写的webpack用法对不对,需要想办法运行编译后的文件才行,有没有觉得很麻烦?我们编译后的文件还需要手动在新建的html文件里面引入,每更改一次文件要想看更新后的效果都还需要在次刷新页面。。。问题多的我已经写不下去了,我们来看看解决之道吧。
webpack插件的概念:一些第三方项目工具包,webpack中引入这玩意能够对整个工程所有代码进行处理,丰富webpack的功能。
html-webpack-plugin插件:引入这位老兄,我们的项目可以自动在编译后的路径中生成html文件,并且自动引用编译后的js文件。
devServer:这个工具可以帮助我们实现热开发,它能在本地启动http服务,我们通过浏览器访问项目。我们的项目代码会被加载到内存中。我们修改了本地的代码,不需要重启服务,项目会自动更新为最新状态。
介绍了这么多我们就来实际操作一遍:
第一步:安装依赖包
//安装html-webpack-plugin
npm install --save-dev html-webpack-plugin
//安装webpack-dev-server
npm install webpack-dev-server --save-dev
第二步:修改webpack.config.js文件
let path = require('path'); //webpack是node写出来的,path是node的语法
let HtmlWebpackPlugin = require('html-webpack-plugin'); //HTML编译插件
module.exports = {
//开发环境
devServer: {
contentBase: './build', //我们把编译后的目录build指定为开发环境
compress: true, //是否展示进度条
port: 9000 //开发环境启动端口
},
mode:'development', //编译环境改成是development(开发模式)
entry:'./src/index.js', //需要编译的源文件目录
output:{ //编译后的目录
filename:'bundle.[hash].js', //编译后的文件名称
path:path.resolve(__dirname,'build') //编译后的路径,必须是绝对路径
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html', //需要编译的html源文件
filename:'indexTest.html', //编译后的文件名
minify:{
collapseWhitespace:true //编译后的html文件去掉空格
}
})
]
}
上述devServer是开发环境热加载功能的部分,HtmlWebpackPlugin是自动打包html文件的插件用法,注意template是需要有一个源文件的,filename指定编译后的目标文件名称(我这里随意指定的,一般取名为index.html)
//./src/index.html源文件,我这里没有指定js文件名称
webpack
第三步:查看html-webpack-plugin编译后的效果
//编译查看效果
npm run build
我在上面的配置中指定了,生成的js文件名称为hash方式,这样可以防止文件没有刷新和缓存引起的问题,我们在源html文件中并未指定生成的js文件会自动引入。
第四步:配置开发环境
就像之前配置npm run build一样,我们配置一下开发环境运行方式为npm run dev
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "webpack-dev-server"
},
接下来我们就可以通过npm run dev来开发我们的项目啦。
为了让浏览器看到效果,我们在通过js文件想html中输入一段文字
//修改我们的index.js文件
document.body.innerHTML= 'devServer and HtmlWebpackPlugin';
在浏览器中输入项目路径即可访问:
http://localhost:9000/indexTest.html
//如果生成的文件名为index.html.可省略文件名,直接用如下方式调用
http://localhost:9000
接下来我们可以随意修改index.js文件的内容,保存之后页面会立即刷新最新数据
样式处理
开发中避免不了需要给页面添加css样式,可是webpack是node开发的,不认识css文件,我们如何让它认识呢?
有一个常接触到朋友叫loader,比如现在有一个css文件我们需要解析怎么办?这个时候我们只要在webpack中添加上style-loader css-loader就可以让webpack识别css文件了。再比如我们css用的是less语法,我们只要在webpack中添加less-loader就又可以用了。看到了吗?loader它就是用于专门处理一类文件的,功能比较单一,一种loader通常只处理一种文件。我们看下示例:
第一步:安装依赖包
//安装解析css的依赖包
npm install --save-dev style-loader css-loader
//安装解析less的依赖包(不用less可不安装)
npm install less less-loader --save-dev
第二步:准备好样式文件
//001.css文件
@import './002.css';
body{
background-color: green;
}
//002.css文件
body{
color:red;
}
//003.less文件
body{
font-size:30px;
}
第三步:要在项目中引入这些样式才能看到效果(主入口文件中引入)
//我这里的主入口文件一直都是index.js(webpack配置文件中的entry:'./src/index.js'选项)
require('./001.css')
require('./003.less')
document.body.innerHTML= 'loader';
第四步:在配置文件中告诉webpack如何解析,添加新的属性(可参考结束语的整个配置文件)
//模块
module:{
//规则:loader特点,希望单一
//loader的用法,字符串只适用于一个loader,多个loader需要用[]
//loader的顺序,默认是从右向左执行
//loader还可以写出对象的方式(好处是可以添加更多的参数)
rules:[
{
test:/\.css$/,
use:[
//css-loader用于机械@import这种语法
//style-loader把css插入到页面中
{
loader:'style-loader'
},
'css-loader'
]
},
{
test:/\.less$/,
use:[
'style-loader',
'css-loader',
'less-loader' //less转换成css文件
]
}
]
}
loader需要放到module下的rules中,一个项目中有各种文件需要解析,因此rules是一个数组,可以配置不同的解析规则。每一个loader配置包含test属性,是一个正则表达式用于匹配文件格式;use则用于指定具体的解析loader。
备注:抽离css可以使用mini-css-extract-plugin
转换es6语法
现在的前端开发避免不了要用到ES6,不过您不了解ES6和babel请跳过本部分知识。
第一步:安装相应的loader
npm install -D babel-loader @babel/core @babel/preset-env webpack
第二步:在webpack配置文件中module下rules中添加文件过滤规则
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets: ['@babel/preset-env'] //指定将ES6转换为ES5
}
}
}
搞定完这两步就可以在项目中使用ES6语法了,想测试的话可以将mode修改为development,然后在编译文件中查看是否有转换成ES5语法。
eslint校验
eslint是项目代码校验工具,能够在项目运行启动之前检查项目语法错误,如果对eslint不是很了解,请先点击链接看下相关文档
第一步:安装eslint和loader
npm install eslint eslint-loader --save-dev
第二步:在webpack配置文件中module下rules中添加文件过滤规则
{
test: /\.js$/,
exclude: /node_modules/, //去掉不需要校验的模块
loader: 'eslint-loader',
options: {
failOnError: true,
},
},
第三步:在项目目录下添加.eslintrc.json文件(注意文件名称前有英文点号)
//.eslintrc.json文件内容,可以根据实际需要自行配置
{
"parserOptions": {
"ecmaVersion": 5,
"sourceType": "script",
"ecmaFeatures": {}
},
"rules": {
"constructor-super": 2,
"for-direction": 2,
"getter-return": 2,
"no-async-promise-executor": 2,
"no-case-declarations": 2,
"no-class-assign": 2,
"no-compare-neg-zero": 2,
"no-cond-assign": 2,
"no-const-assign": 2,
"no-constant-condition": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-dupe-args": 2,
"no-dupe-class-members": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty": 2,
"no-empty-character-class": 2,
"no-empty-pattern": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
"no-extra-semi": 2,
"no-fallthrough": 2,
"no-func-assign": 2,
"no-global-assign": 2,
"no-inner-declarations": 2,
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-misleading-character-class": 2,
"no-mixed-spaces-and-tabs": 2,
"no-new-symbol": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-prototype-builtins": 2,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-self-assign": 2,
"no-shadow-restricted-names": 2,
"no-sparse-arrays": 2,
"no-this-before-super": 2,
"no-undef": 2,
"no-unexpected-multiline": 2,
"no-unreachable": 2,
"no-unsafe-finally": 2,
"no-unsafe-negation": 2,
"no-unused-labels": 2,
"no-unused-vars": 2,
"no-useless-catch": 2,
"no-useless-escape": 2,
"no-with": 2,
"require-atomic-updates": 2,
"require-yield": 2,
"use-isnan": 2,
"valid-typeof": 2
},
"env": {
"browser": true,
"node": true
}
}
第四步:编写文件,开启项目或者编译项目检查eslint是否正确配置
//在index.js文件中添加如下代码启动项目,可以看到如图所示的错误
var foo = bar;
即:
'foo' is assigned a value but never used no-unused-vars
'bar' is not defined no-undef
引入第三方插件和全局变量
有时候可能需要在项目中引入jquery等第三方库,该怎么做呢?
首先不必多说肯定是引入jquery
npm run jquery
然后可以直接在想用jquery的地方引入jquery即可
//node的方式
let $ = require('jquery');
//ES6的方式
import $ from 'jquery'
不过上述引入jquery方式都只是在单个模块内部,也就是说每个模块文件想用jquery都得重新引入一次jquery才行,不能通过window获取jquery对象。但如果你就希望通过window.$来用怎么办呢?
方式一:通过expose-loader插件把$暴露到全局window对象上
//安装expose-loader
npm run expose-loader
//在文件中引入jquery(不可缺少)
let $ = require('jquery');
//在module下rules中添加文件过滤规则
{
test:require.resolve('jquery'),
use:'expose-loader?$'
},
//至此可以console.log(window.$)获取全局$对~~~~象
方式二:一次性在所有模块中注入$对象,这种方式并不会jquery暴露到window对象上,但是每个模块在使用$的时候也不需要在引用jquery了
//在配置文件中引入webpack
let webpack = require('webpack');
//在配置文件中plugins添加如下插件
new webpack.ProvidePlugin({
$:'jquery'~~~~
})
方式三:直接在页面的