引言
webpack是模块化打包工具,是由node构建的,webpack通常会将入口文件以及它的依赖还有每个分支的依赖整理打包,打包后的项目的文件数量还有文件体积会大大减少,并且会自动转化一些内容;比如把浏览器不识别的es6/es7...转化成浏览器能识别的es5
模块化
esmodule
导出:
- export
- export default
导入:
- import * as xxx from "yyy.js
- import xxx from "yyy.js"
- import {xxx} from "yyy.js"
commJs
commJS是node的模块化规范 导出:
- module.exports
- exports.xxx
导入:
- let xxx=require("yyy.js")
浏览器与模块化
无论是使用esModule,还是commJs规范实现模块化开发(在js中引入其他js暴露的内容,在当前模块使用-->一个模块就是一个js文件);如果使用了esModule,还不在引用时的 script标签中添加type="module"属性(一般浏览器不支持type属性)或者使用commJS规范实现模块化开发,在浏览器端都是不能识别的;也就是当你要使用多个js文件并且文件之间还有依赖的情况下,只能在html文件中引入多个script,但是这样会在客户端渲染页面的时候,发送多个http请求,影响请求效率;这个时候就要用到webpack打包工具,从入口文件开始,把它所有依赖的文件整合处理成一个文件
webpack的大致应用
webpack会把遇到的以下内容进行转化
- less/sass-->css
- typescript-->javascript
- es6/es7...-->es5
- 图片-->base64
webpack4.0的零配置
使用前要初始化一个packge.json,记载着包的菜单
npm init -y
然后安装webpack以及webpack-cli
npm init webpack webpack-cli -D
安装完成后,在命令窗口执行
npx webpack
npm run build(在package.json的脚本中配置build)
yarn build
全局安装的命令可以直接执行
webpack
但是一般不会这么做,因为不同项目会有冲突不建议全局安装
如果执行打包命令时没有配置webpack.config.json/webpackfile.js文件就是零配置没有指定入口文件出口文件,默认入口文件scr/index.js,出口文件dist/main.js 也就是说在没有配置文件的情况下会自动把src/index.js文件及其内部依赖打包成 dist文件夹下的main.js
(-D 代表--save-dev 表示这个npm包只有在开发时使用)
webpack配置
定义一个webpack.config.js文件
var path = require('path')
module.exports = {
mode: 'development',//webpack4新增的,development,production
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.reslove(__dirname, 'dist'),
filename: 'bundle.js'
}
}
webpack-dev-server
安装插件
npm i webpack-dev-server -D
var path = require('path')
module.exports = {
mode: 'development',//webpack4新增的,development,production
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.reslove(__dirname, 'dist'),
filename: 'bundle.js'
},
devServer:{
open:true,
port:3000,
constbase:path.resolve(__dirname,dist).
compress:true
}
}
devServer参数
| 参数 | 作用 |
|---|---|
| open | 当入口文件更新时自动生成bundle.js文件后浏览器自动打开 |
| port | 设定访问的端口号 |
| host | 设置访问的主机ip地址 |
| constbase | 服务默认去找项目根目录的index.html,此参数改变服务请求的文件夹 |
| hot | 热更新,正常情况下每改变一次都要重新生成完整bundle.js,而此时只需要重新生成更新的内容即可,并实现浏览器的无刷新 ,相当于ajax的效果 |
设置之后在package.json文件添加脚本
dev:"webpack-dev-serve"
之后直接执行
npm run dev,开启服务,每当打包内容有变化就会自动重新修改内容,实现实时更新
html-webpack-plugin
npm install html-webpack-plugin -D
let HtmlWebpckPlugin=require("html-webpack-plugin")
var path = require('path')
module.exports = {
mode: 'development',//webpack4新增的,development,production
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.reslove(__dirname, 'dist'),
filename: 'bundle,[hash:6].js'
},
devServer:{
open:true,
port:3000,
constbase:path.resolve(__dirname,dist).
compress:true
},
plugins:[
new HtmlWebpckPlugin({
//原tml文件路径
template:path.join(__dirname,"./src/index.html"),
//打包后的html文件名
filename:"index.html",
//title使用的前提是在html页面上<%= htmlWebpackPlugin.tags.bodyTags%>
title:"haha"
//html文件的压缩,
minify:{
//除空格
collapseWhitespace: true,
//移除标签属性值的双引号
removeComments: true,
//移除空属性
removeRedundantAttributes: true,
}
})
]
}
每次打包完会自动把打包好的js文件插入到html中
clear-webpack-plugin
cnpm i clear-webpack-plugin -D
html文件要引入打包好的js文件(使用html-webpack-plugin会自动引入),
script标签在页面内,解析页面结构时遇到script发送get请求,浏览器对get请求是有缓存的,所以要保证只要打包的内容改变打包后生成的js文件名不同,因此就在出口文件bundle.[hash:6].js,加上hash每次内容改变生成的打包后的文件的hash值都会改变,那么上次生成的文件就没有用了,使用clear-webpack-plugin可以删除没有使用的打包后文件,也可以在html-webpack-plugin插件配置中配置hash,这样就会在引入
script时 为文件名自动添加hash值
安装
npm i clear-webpack-plugin -D
let HtmlWebpckPlugin=require("html-webpack-plugin")
let {ClearWebpckPlugin}=require("clear-webpack-plugin")
var path = require('path')
module.exports = {
mode: 'development',//webpack4新增的,development,production
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.reslove(__dirname, 'dist'),
filename: 'bundle,[hash:6].js'
},
devServer:{
open:true, //是否打开浏览器
port:3000, //端口号
constbase:path.resolve(__dirname,dist), //指定资源访问路径
compress:true, //是否开启GZIP压缩
progress:false, //是否显示编译进度
hot:true, //是否开启热更新
proxy:{ //跨域代理
"/": "http://..."
}
},
plugins:[
new HtmlWebpckPlugin({
//原tml文件路径
template:path.join(__dirname,"./src/index.html"),
//打包后的html文件名
filename:"index.html",
//title使用的前提是在html页面上<%= htmlWebpackPlugin.tags.bodyTags%>
title:"haha"
//html文件的压缩,
minify:{
//移除标签之间空格
collapseWhitespace: true,
//移除标签属性值的双引号
removeAttributeQuotes:true
//移除注释
removeComments: true,
//移除空属性
removeRedundantAttributes: true,
}
}),
new ClearWebpckPlugin()
]
}
多入口多页面的打包配置
多入口文件要在entry中为不同的文件设置名称(是key值),为output中的filename设置[name].[hash].js,得到相应个数的出口文件,有几个页面就要new几个HtmlWebpackPlugin,里面的chunks对应的数组元素就是入口文件的name,想要引入哪个打包后的文件就把name放到数组中,如果有像jquery这种想要单独作为一个入口文件就直接安装jquery yarn add jquery,然后直接把他放到entry对象中,在要引入他的html中的chunks添加它的name值
let HtmlWebpckPlugin=require("html-webpack-plugin")
let {ClearWebpckPlugin}=require("clear-webpack-plugin")
//index与login最好是html的文件名
//修改处
let htmlPlugin=["index","login"].map(item=>{
return new HtmlWebpckPlugin({
//原tml文件路径
template:path.join(__dirname,`./src/${item}.html`),
//打包后的html文件名
filename:`${item}.html`,
//title使用的前提是在html页面上<%= htmlWebpackPlugin.tags.bodyTags%>
title:"haha"
chunks;[item]
//这个页面要引入的打包后的文件的name,就是在entry中定义的key
//html文件的压缩,
minify:{
//移除标签之间空格
collapseWhitespace: true,
//移除标签属性值的双引号
removeAttributeQuotes:true
//移除注释
removeComments: true,
//移除空属性
removeRedundantAttributes: true,
}
})
})
var path = require('path')
module.exports = {
mode: 'development',//webpack4新增的,development,production
//修改处
entry: {
index:path.join(__dirname, './src/index.js'),
login:path.join(__dirname,'./src/login.js')
}
output: {
path: path.reslove(__dirname, 'dist'),
//修改处
filename: '[name].[hash:6].js'
//这里的name就是entry中的key
},
devServer:{
open:true, //是否打开浏览器
port:3000, //端口号
constbase:path.resolve(__dirname,dist), //指定资源访问路径
compress:true, //是否开启GZIP压缩
progress:false, //是否显示编译进度
hot:true, //是否开启热更新
proxy:{ //跨域代理
"/": "http://..."
}
},
plugins:[
...htmlPlugin,
new ClearWebpckPlugin()
]
}
解决css文件的引入
当入口文件或者他依赖的js文件中引入了css文件,现有的配置是不能支撑webpack的打包的,他还要安装很多的loader并完成配置,使得引入得css文件在打包之后可以使用 首先要安装一些loader:
yarn add style-loader css-loader postcss-loader less-loader less sass sass-loader node-sass autoprefixer -D
let HtmlWebpckPlugin=require("html-webpack-plugin")
let {ClearWebpckPlugin}=require("clear-webpack-plugin")
//index与login最好是html的文件名
let htmlPlugin=["index","login"].map(item=>{
return new HtmlWebpckPlugin({
//原tml文件路径
template:path.join(__dirname,`./src/${item}.html`),
//打包后的html文件名
filename:`${item}.html`,
//title使用的前提是在html页面上<%= htmlWebpackPlugin.tags.bodyTags%>
title:"haha"
chunks;[item]
//这个页面要引入的打包后的文件的name,就是在entry中定义的key
//html文件的压缩,
minify:{
//移除标签之间空格
collapseWhitespace: true,
//移除标签属性值的双引号
removeAttributeQuotes:true
//移除注释
removeComments: true,
//移除空属性
removeRedundantAttributes: true,
}
})
})
var path = require('path')
module.exports = {
mode: 'development',//webpack4新增的,development,production
entry: {
index:path.join(__dirname, './src/index.js'),
login:path.join(__dirname,'./src/login.js')
}
output: {
path: path.reslove(__dirname, 'dist'),
filename: '[name].[hash:6].js'
//这里的name就是entry中的key
},
devServer:{
open:true, //是否打开浏览器
port:3000, //端口号
constbase:path.resolve(__dirname,dist), //指定资源访问路径
compress:true, //是否开启GZIP压缩
progress:false, //是否显示编译进度
hot:true, //是否开启热更新
proxy:{ //跨域代理
"/": "http://..."
}
},
module:{
rules:[{
test:/\.(less|css)$/i,
use:[
style-loader, //把拿到的css内嵌到页面中
//
css-loader, //解析@import/url
postcss-loader, //为样式加上前缀(这里要配合插件使用)
{
loader:less-loader, //把less转成css
options:{}
}
]
}]
},
plugins:[
...htmlPlugin,
new ClearWebpckPlugin()
]
}
上面提到的postcss-loader,为样式加上前缀的要配合一个文件使用(postcss.config.js)在文件中
module.exports={
plugins:[
require('autoprefixer')
]
}
还要再package.json文件中浏览器的兼容范围
"browserslist":[
"> 1%",
"last 2 versions"
]
最后使用style-loader会把得到的样式内嵌到页面中,但是如果想要外链式的样式就要使用插件(min-css-extract-plugin)抽离样式到一个文件再引入
首先要安装
yarn add min-css-extract-plugin
在配置文件中引入
let HtmlWebpckPlugin=require("html-webpack-plugin")
let {ClearWebpckPlugin}=require("clear-webpack-plugin")
let MinCssExtractPlugin=require("min-css-extract-plgin")
//index与login最好是html的文件名
let htmlPlugin=["index","login"].map(item=>{
return new HtmlWebpckPlugin({
//原tml文件路径
template:path.join(__dirname,`./src/${item}.html`),
//打包后的html文件名
filename:`${item}.html`,
//title使用的前提是在html页面上<%= htmlWebpackPlugin.tags.bodyTags%>
title:"haha"
chunks;[item]
//这个页面要引入的打包后的文件的name,就是在entry中定义的key
//html文件的压缩,
minify:{
//移除标签之间空格
collapseWhitespace: true,
//移除标签属性值的双引号
removeAttributeQuotes:true
//移除注释
removeComments: true,
//移除空属性
removeRedundantAttributes: true,
}
})
})
var path = require('path')
module.exports = {
mode: 'development',//webpack4新增的,development,production
entry: {
index:path.join(__dirname, './src/index.js'),
login:path.join(__dirname,'./src/login.js')
}
output: {
path: path.reslove(__dirname, 'dist'),
filename: '[name].[hash:6].js'
//这里的name就是entry中的key
},
devServer:{
open:true, //是否打开浏览器
port:3000, //端口号
constbase:path.resolve(__dirname,dist), //指定资源访问路径
compress:true, //是否开启GZIP压缩
progress:false, //是否显示编译进度
hot:true, //是否开启热更新
proxy:{ //跨域代理
"/": "http://..."
}
},
module:{
rules:[{
test:/\.(less|css)$/i,
use:[
//修改
MinCssExtractPlugin.loader,
//把拿到的css放到文件中link到页面
css-loader, //解析@import/url
postcss-loader, //为样式加上前缀(这里要配合插件使用)
{
loader:less-loader, //把less转成css
options:{}
}
]
}]
}
plugins:[
...htmlPlugin,
new ClearWebpckPlugin(),
//修改
new MinCssExtractPlugin({
filename:"[name].[hash].min.css"
//这里的name还是入口entry处的name,hash还是为了防止浏览器的缓存使页面得不到最新数据x
})
]
}
css和js的优化压缩
首先要安装yarn add optimize-css-assets-webpack-plugin(css) uglifyjs-webpack-plugin(js) terser-webpack-plugin(js不常用) -D
const UglifyjsWebpackPlugin=require("uglifyjs-webpack-plugin")
const TerserWebpackPlugin=require("terser-webpack-plugin")
const OptimizeCssAssetsWebpackPlugin=require("optimize-css-assets-webpack-plugin")
module.exports={
optimization:{
minimizer:[
new TerserWebpackPlugin(),
new OptimizeCssAssetsWebpackPlugin()
]
}
}
图片的引入
图片正常会在css文件作为背景时出现,在js中动态创建img元素并赋值src属性,在html页面中出现引用图片的情况,同样目前的配置无法加载图片,也无法把图片打包到dist文件中,所以就要对配置文件进行进一步的配置
首先安装loader
yarn add file-loader url-loader html-widthimg-loader
module.exports={
module:{
rules:[{
test:[{
test:/\.(png|jpe?g|gif)$/i,
use:[{
loader:'url-loader',
options:{
limit:200*1024,
outputPath:"./images",
name:"[name].[hash].[ext]",
esModule:false
}
}],
include:path.resolve(__dirname,"src"),
exclude:/node_modules/
},{
test:/\.(svg|eot|ttf|woff|woff2)$/i,
use:"file-loader"
},{
//找到html中的图片把他按照上面的规则执行
test:/\.html$/,
use:["html-withingimg-loader"]
}]
}]
}
}
这里的url-loader是指在图片大小,小于limit的情况下直接base64处理,而在大于limit的情况下就要交给file-loader处理,outputPath就是打包后图片放入的文件路径,name是打包后没有转成base64的图片名称,打包后文件中图片的地址也会改变,这是指在css中的图片,在js中的src属性要通过require来引入要得到的相对路径的图片,而其他网站绝对路径的图片地址不受影响,加入esModule:false属性才能成功
实现js的转换
正常情况下webpack根据es6Module和CommonJS规范把js打包成一个文件,但是他不会把es6和es7的语法转化成es5的,这样当我们要兼容更低版本的浏览器的时候就做不到了,可以利用babel对js进行转换 安装:
yarn add babel-loader @bebal/core @bebal/perset-env(转换包把es6转成es5) -D
除了转换包之外还有一些插件可以用来转化一些语法
yarn add @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators -D
yarn add @babel/plugin-transform-runtime @babel/runtime @babel/polyfill -S
moudle.exports={
module:{
rules:[{
test:/\.js$/i,
use:[{
loader:"babel-loader",
options:{
persets:[
//es6=>es5
"@babel/preset-env"
],
plugins:[
//es7装饰器
["@babel/plugin-proposal-decorators",{ "legacy":true
}],
//es7的属性
["@babel/plugin-proposal-class-properties",{ "loose":true
}],
//协助@babel/polifll,在运行时校验js的转换
"@babel/plugin-transform-runtime"
]
}
}],
include:path.resolve(__dirname,"src"),
exclude:/node_modules/
}]
}
}
特别注意@babel/plugin-transform-runtime @babel/runtime @babel/polyfill他们是安装在生产环境下的为了在代码运行的时候js转化