认识
什么是webpack?
本质上来讲,是现代js应用的静态模块化打包工具,核心解释为 模块化 和 打包 官方图:
项目中的:
图片:png,jpg
样式:css、scss、less,saas
js:vue、react,es6
浏览器只能变异运行 css,js,html,png,jpg
中间就需要webpack转换
模块化
- 前端模块化势在必行,大项目,多人合作越来越多
- 模块化方案:ES6,CommonJS
- 在ES6之前,我们想要进行模块化开发必须借助其他工具,让我们能够进行模块化开发
- 并且通过模块化开发完成了项目之后,还需要处理各模块之间的依赖,并且将其整合打包
- 而webpack其中一个核心就是可以让我们进行模块化开发,并且会帮助我们进行处理模块之间的依赖关系
- 而且不仅是js文件,我们的css,图片,json文件等在webpack中都可以被当成模块来使用
- 这就是webpack模块化的概念
打包
就是webpack帮我们进行模块化,处理了模块之间依赖关系之后,将各种资源整合成一个或多个包(Bundle) 并且在打包过程中,还可以对资源进行处理,比如压缩图片,scss 转换成 css,将ES6语法转换成ES5语法,将TS转换成JS等等
安装
webpack依赖node环境,node环境为了能够正常执行代码,需要依赖很多包,这些包通过npm包管理工具管理 安装node,得到自带的npm 全局或局部安装 webpack
全局安装:
npm install webpack@latest -g
局部安装
npm install webpack@latest --save-dev
--s全部e-dev是开发时依赖,项目打包后不需要继续使用的
为什么全局安装后还需要局部安装呢? 在终端直接输入webpack命令,走的全局 当package.json中定义了scripts时,其中定义了webpack命令,那么使用的是局部
起步
全局配置
webpack配置,如果是终端里边执行webpack的都是使用全局安装的webpack,此时通过
webpack entry output的方式,说明webpack执行时候,从那个入口开始收集依赖&打包,输出在哪个位置,index.html中只需要引入output中的打包后的js就可以了
配置
项目中配置
全局的webpack和局部项目中的webpack可能存在版本不同的情况,一般在项目中我们用项目本地webpack居多。
项目中,只要涉及到npm包的使用,我们必然会进行包安装和版本管理等,因此必须通过npm init 在项目根目录下来创建package.json。
只要下载了包,package.json 中就会有包的使用情况,根据包是本地开发使用还是发布后仍需要使用,安装时看要不要加--save-dev,加了该参数的
安装完,packages.json统计目录出现node_modules文件夹,除了.bin文件还有其他包依赖的文件,.bin中保存着包的执行指令
package.json定义启动
项目中,我们通过script脚本进行运行,在script中配置命令名称,对应执行的脚本(key:value),通过npm run key就会自动执行value
script 脚本执行的时候,会按照一定的顺序寻找对应命令的位置。
- 首先,会寻找本地node_modules/.bin路径下寻找对应的命令
- 如果没有找到,去全局寻找
为什么上图中build只配置webpack命令即可,因为webpack执行时候,要么在命令行写入口出口,(比较长),要么在固定的webpack.config.js中写webpack 配置
以上述为demo,打包之后,
首页引用
loader使用
loader是webpack 的核心概念
webpack用来做什么:
- 在我们之前的demo中,主要用来处理我们写的js代码,并且自动处理js模块之间的依赖
- 但是,在开发中我们不仅仅有基本的js代码处理,我们还需要加载css,图片,也包括一些高级的es6需要专程浏览器识别es5,以及ts转换为js,还有把scss,less转换成css,将.jsx.vue.react转化成js文件等等。
- 对于webpack本身的能力来讲,对于这些转化是不支持的。 那怎么办?给webpack扩展对应的loader就可以
loader使用过程:
- 通过npm 安装需要的loader,不同功能需要不同的loader,查看loader官网webpack.docschina.org/loaders/#st…
- 为webpack.config.js中的module关键字下进行配置
css demo
增加css模块,在main.js通过COMMONJS 模块化方案引用,统一打包到dist/bundle.js生效。
- 默认webpac只能处理js,提示需要对css安装合适的loader,我们使用了css-loader,
- 下载css- loader,配置webpack.config.js的module
- css-loader只负责加载css文件,样式渲染DOM需要另一个style-loader下载并配置
- webpack读取use是从右往左,先加载css文件,再渲染
less demo
- 建立less文件
- 引用less文件
- 下载less 的loader
- 配置less的loader
建立文件:
入口文件引用文件
直接build报错
官网查询合适的less loader
配置webpack loader
打包顺序
图片demo
1、本地准备图片
2、css背景换成url('imgPath')
直接打包报错
3、下载图片loader
我们在官网查找到图片的常用loader:url-loader,下载
4、配置webpack 图片loader
大图与小图区别
大图:大图指的是图片大小大于8KB*1024=8192Byte
运行发现,提示需要安装file-loader,安装后 发现页面什么也没有展示
我们发现2个现象:
- body{backround: url(***.jpg)}
- 控制台出现一个找不到图片的404报错
原因:查找url地址是相对于index.html目录下查找当前目录下****.jpg并未找到导致的,我们打包出的图片位置在dist下,❤新生成了一个图片文件,位置在dist/*.jpg而非index.html同级别下的jpg,因此有404错误。
如何解决? 只要将index.html中对url(图片文件)的引用路径改为 dist/ 即可,修改方式:
修改后,我们发现页面展示成功了
延伸:
我们发现本地用到的图片多了,打包后都放在dist下,且名字都是32位hash值,难以区分,因此url-loader提供了对于打包后图片输出路径及名称的配置入口,即name
基于以上配置,以后所有的图片都打包在dist/img中,且名字都有固定队则,如下图
此时页面正常展示
小图:小图指的是图片大小于8KB*1024=8192Byte
这里的8KB只是默认,到底是以大图还是小图打包依赖于limit的配置,
由于没找到小图,为了测试,我把limit改大了,大于我的图片,打包发现,并未生成img/**文件
而页面能够正常展示:
url(data:image/jpeg:base64,*****)
图片打包总结
- 用到url引入图片就会涉及到入片相关loader,涉及到两个loader:url-loader和file-loader
- 二者作用相近,一般只需要配置url-loader,在limit处配置图片大小临界值,小于limit,url-loader直接处理,将图片编译为base64编码的字符串;大于limit,就会交由file-loader结合处理,他处理的会生成新文件。file-loader需单独下载,但配置写在url-loader里。
- 配置什么?两个:publicPath(output里配置)+name(url-loader options里配置)。
- 前者配什么?经过file-loader处理的会在出口文件夹生成新文件,但是index.html一般与dist同级,而打包生成的文件在dist下。但是index.html的url引用时默认同级,会出现404找不到文件(在dist下),因此需要配置index.html通过url引用文件时的公共path,publicPath
- 后者配什么?file-loader处理的文件多了,都放在dist下,名字都是32位哈希,无法区分。可以把图片都打包在dist/img文件夹里,且给固定规则的名称用来区分,因此出现了后者的配置name(url-loader options里配置)
babel-loader
上述的例子我们发现,通过es6写的代码打包后的bundle.js 仍然是es6的语法形式存在,有些浏览器可能不支持,为了解决这个问题,我们需要使用将es6转位es5的loader,即babel-loader
安装
npm install babel-loader@7 babel-core babel-preset-2015
babel- loader的核心是 babel-core需要都下载,且需要声明处理的js版本?
配置
运行发现,bundle里没有es6语法了,代码正常运行
webpack中配置Vue
1、vue安装
下载引用 CDN. npm
2、Vue 引用
inport Vue from 'vue'
查找vue去node_modules/vue中取,vue有两个核心模块,runtime-only & vue-compiler。前者不包含对<template>的解析。因此对于<tempalte>的解析,所以我们需要使用后者,后者需要让加载vue时在node-modules/vue/dist/vue.esm.js去取。
想让import vue from vue 后者的vue从指定位置取,需要webpack resolve配置
需要特殊配置resolve
new Vue({options})
3、vue-loader下载配置
下载两个,vue-loader + vue-template-comliler,核心在后边。类似的loader搭配还有
less-loader + less
babel-loader + babel-core
vue 中el 和 template区别
template和el同时配置,template会替代el
plugin使用
是什么?
- 插件,通常是对于现有某个框架的扩展
- webpack中的插件,则是对webpack现有功能的扩展,比如打包优化,文件压缩等(有内置插件+外部插件)
loader和plugin的区别?
- loader用于非js类模块的加载和转换,是一个转换器+加载器。负责文件的转换和加载
- plugin则用于一些功能的扩展,是一个扩展器。
使用?
- 通过npm安装需要使用的plugin.内置的不需要安装。
- 在webpack的配置文件中,配置插件
plugin demo-版权插件
内置插件,无需下载,直接配置使用。配置如下
打包后的bundle.js第一行就会出现版权信息
其他插件介绍
htmlWebpackPlugin
我们之前的demo,我们说打包之后将dist下文件整个放到服务器就可以,但是现在缺少index.html.他在根目录而不在dist.
为了让index.html 自动放在dist中,我们需要htmlwebpackplugin,他有两个功能:
- 自动在出口文件夹中生成一个index.html
- 在生成的index.html中通过script标签引入出口文件bundile.js
- 下载
- 配置
- 打包
但是我们发现,生成的index.html两点不满足需求:
- 没有id=app
- src路径不正确
解决方案: 1、缺少id=app 我们定制一个index.html让根据该模板生成,该模板中,写入id=app(script不需要是自动插入的),再配置插件,指明给予什么模板生成
2、src路径问题
最终在dist/index.html
浏览器访问dist/index.html
js压缩插件-uglifyjs-webpack-plugin
我们打包的buldle.js比较大,可以通过该插件压缩,主要把空行,空格、注释去除,变量名简化等
- 安装
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev - 配置
- 使用对比
压缩前
压缩后
搭建本地服务器
以上运行在dist/index.html下的应用,每次修改页面,都需要重新build,再刷新页面,浪费时间。webpack提供了一个内置服务器,可以服务于某个文件夹,让这个文件夹相关的源码,只要有改动,浏览器自动刷新。此时用到了webpack-dev-server.
- 下载
npm install webpack-dev-server@2.9.3 --save-dev - 配置 在webpack.config.js单独配置devServer
- 启动服务器
./node_modules/.bin/webpack-dev-derver启动了8080端口,访问,页面正常展示,修改页面内容,自动刷新
对于长的指令,我们通过script脚本形式,配置命令"dev":"webpack-dev-server"之后终端执行npm run dev效果相同
为了让执行脚本自动打开浏览器,在指令后增加参数--open
修改任何内容,发现终端展示webpack compilering,重新打包,打包后页面正常展示,但是dist内容没变
比如,我本地修改了背景图片22.jpg改成了111.jpg,此时重新打包:
页面正常展示,背景已经替换
但是,项目中的dist并没有变化
webpack配置分离
指的是开发和发布时,webpack配置有区别,从而进行配置的分离。 以我们的demo为例,代码压缩则无法本地调试,因此这部分在发布时才需要;devServer只有本地开发才需要,因此我们就根据场景不同,将配置文件分离开来。
所有和打包相关的配置我们新建一个build文件夹,里边建立三个配置文件:
- base.config.js:基本的配置,两个环境都需要的放在这里
- dev.config.js:开发时需要的配置
- prod.config.js:往服务器发布时需要的配置 我们的例子中,需要把new UhlifyjsWebpackPlugin() 的代码压缩放在prod.config.js中,将devServer相关配置放在dev.config.js中
记得其他环境需要mergeBaseConfig,依赖这个包webpack-merge
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: "./main.js",
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js',
// publicPath: 'dist/'
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['.js', '.css', '.vue']
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
}
]
},
{
test: /\.less$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'less-loader'
}
]
},
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8196,
name: 'img/[name].[hash:8].[ext]'
}
}
]
},
{
test: /\.vue$/,
use: [
{
loader: 'vue-loader'
}
]
}
]
},
plugins: [
new webpack.BannerPlugin('版权归我moxiaoqian所有!'),
new HtmlWebpackPlugin({
template: 'index.html'
})
]
}
const WebpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')
module.exports = WebpackMerge(baseConfig, {
devServer: {
contentBase: './dist',
inline: true,
}
})
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const WebpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')
module.exports = WebpackMerge(baseConfig, {
plugins: [
new UglifyjsWebpackPlugin()
]
})
此时webpack.config.js就可以删除了,但是删除了script中脚本执行的时候就会找不到这个配置文件。当然我们现在也不需要让执行这个文件了。而是让dev去执行本地打包。build走prod打包。此时需要配置命令:如下
此时去执行发现,dist打包在build下了
原因是,webpack打包的时候,找到配置文件,出口在
path.resolve(__dirname, 'dist'),即 build/dist
如果想让继续输出在项目根目录,那么我们修改output为 path.resolve(__dirname, '../dist')
这样就OK了
配置分离需要注意的几个路径问题
入口和index模板的获取,还是在根目录下,和base.config.js位置没关系,可以理解为引入的webpack配置内容不管写在哪个位置,export导出后,默认在根目录使用,但是输出的output用到了
path.RESOLVE(__dirname) 取的是实实在在的文件位置,因此这里需要变化