webpack
- webpack的机制,它就是个模块打包器,默认只支持JS模块;
1、npm init -y 初始化
- webpack安装,不推荐全局安装,因为可能你的项目,是不同版本的webpack
- package.json,name名不要起webpack,不然无法安装 wepback
{
"name": "webpack_study",
}
2、npm install webpack webpack-cli --save-dev // -D
- 如何查看webpack 版本
- webpack -v 如果你之前全局安装了webpack,那么会看到你装的版本
- 这里如果只想查看,我现在项目的webpack 版本
- 使用 npx webpack -v
3、 安装指定版本
- npm info webpack 罗列出我们可以快速安装的webpack版本
- npm install webpack@x.xxx webpack-cli -D
- 安装指定版本的webpack
4、 新建默认的入口文件 index.js
function kkb(){
console.log(`欢迎看到webpack`)
}
kkb();
- webpack默认情况它只认识js文件,它以入口文件index.js,来进行打包。
- 打包命令 npx webpack index.js
- 会给你生成一个dist文件夹目录,index.js 会给你打包成main.js
5、webpack 配置文件
-
新建 webpack.config.js
-
可以在里面定制我们的webpack
-
零配置很弱,特定的需求,总是需要自己配置;
-
当我们使用npx webpack index.js打包时,表示的是使用webpack 处理打包,名为index.js的入口模块,默认放在当前目录下的dist文件夹,打包后的模块名称是main.js,当然我们可以修改。
-
webpack 有默认的配置文件,叫webpack.config.js,我们可以对这个文件进行修改,进行个性化配置
-
默认的配置文件:webpack.config.js
-
npx webpack //执行命令后,webpack会找到默认的配置文件,并使用执行。
-
不使用默认的配置文件:webpackconfig.js
-
npx webpack --config webpackconfig.js // 指定webpack使用webapckconfig.js文件作为配置文件并执行
-
修改package.json script字段:
"scripts": {
"bundle": "webpack"
}
- 这样我们就可以不用 npx webpack 来进行打包命令,可以使用 npm run bundle 来进行打包
6、file-loader
-
npm install file-loader -D
-
webpack.config.js 配置文件 备注:遇到后面带S的参数往往是个数组[]
const path = require('path')
module.exports = {
// 打包入口文件
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, ' build'),
filename: 'index.js'
},
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.{png|jpe?g|gif}$/,
rules: [
{
test:/.jpg$/,
use: {
loader: 'file-loader', // 就是把模块,放在另外一个目录里,并且把位置返回给我们
options: {
// name 是打包前模块的名称,ext是打包前的模块格式
name: '[name]_[hash].[ext]',//team_哈希值.jpg
outputPath: 'images/' //图片打包后存放目录
}
}
}
]
}
}
7、url-loader 是 file-loader 加强版
- npm install url-loader -D
const path = require('path')
module.exports = {
// 打包入口文件
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, ' build'),
filename: 'index.js'
},
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.(png|jpe?g|gif)$/,
// 不光可以处理图片,还可以处理 视频,音频,只要后缀格式正确
rules: [
{
test:/.(png|jpe?g|gif)$/,
use: {
// url-loader 可以限定模块体积,根据体积判断是否需要转换成base64,减少http请求
loader: 'url-loader',
// file-loader就是把模块,放在另外一个目录里,并且把位置返回给我们,同时还适合第三方字体,svg之类的
options: {
name: '[name]_[hash].[ext]',
// name 是打包前模块的名称,ext是打包前的模块格式 team_哈希值.jpg
outputPath: 'images/',
//图片打包后存放目录
limit: 2048
//如果小于 2048 2KB的图片,会被转成base64位格式图片
}
}
}
]
}
}
8、如何打包 CSS文件
-
需要安装 2个依赖
- npm install style-loader -D
- npm install css-loader -D
-
css-loader 让webpack 认识css模块,代码集成,然后进行打包
-
style-loader 把css-loader 打包的css文件,以style的方式,放在HTML头部
const path = require('path')
module.exports = {
// 打包入口文件
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, ' build'),
filename: 'index.js'
},
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.(png|jpe?g|gif)$/,
// 不光可以处理图片,还可以处理 视频,音频,只要后缀格式正确
rules: [
{
test:/.(png|jpe?g|gif)$/,
use: {
// url-loader 可以限定模块体积,根据体积判断是否需要转换成base64,减少http请求
loader: 'url-loader',
// file-loader就是把模块,放在另外一个目录里,并且把位置返回给我们,同时还适合第三方字体,svg之类的
options: {
name: '[name]_[hash].[ext]',
// name 是打包前模块的名称,ext是打包前的模块格式 team_哈希值.jpg
outputPath: 'images/',
//图片打包后存放目录
limit: 2048
//如果小于 2048 2KB的图片,会被转成base64位格式图片
}
}
},
{ // 打包的css它会在 index.html head标签 的style中
test: /.css$/,
use: ['style-loader','css-loader']
}
]
}
}
9、sass or less 如何打包
- sass == xxx.scss
- less == xxx.less
- scss 格式
- npm install sass-loader node-sass --save-dev
- 安装比较久,需要耐心等待
const path = require('path')
module.exports = {
// 打包入口文件
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, ' build'),
filename: 'index.js'
},
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.(png|jpe?g|gif)$/,
// 不光可以处理图片,还可以处理 视频,音频,只要后缀格式正确
rules: [
{
test:/.(png|jpe?g|gif)$/,
use: {
// url-loader 可以限定模块体积,根据体积判断是否需要转换成base64,减少http请求
loader: 'url-loader',
// file-loader就是把模块,放在另外一个目录里,并且把位置返回给我们,同时还适合第三方字体,svg之类的
options: {
name: '[name]_[hash].[ext]',
// name 是打包前模块的名称,ext是打包前的模块格式 team_哈希值.jpg
outputPath: 'images/',
//图片打包后存放目录
limit: 2048
//如果小于 2048 2KB的图片,会被转成base64位格式图片
}
}
},
{ // 打包的css它会在 index.html head标签 的style中
test: /.css$/,
use: ['style-loader','css-loader']
},
{
test: /.s[ac]ss$/i,
// loader 是有执行顺序的,从后往前
use: ['style-loader','css-loader','sass-loader']
}
]
}
}
10、样式自动添加浏览器前缀-Postcss-loader
- npm install -D postcss-loader
- webpack.config.js 引入使用
const path = require('path')
module.exports = {
// 打包入口文件
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, ' build'),
filename: 'index.js'
},
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.(png|jpe?g|gif)$/,
// 不光可以处理图片,还可以处理 视频,音频,只要后缀格式正确
rules: [
{
test:/.(png|jpe?g|gif)$/,
use: {
// url-loader 可以限定模块体积,根据体积判断是否需要转换成base64,减少http请求
loader: 'url-loader',
// file-loader就是把模块,放在另外一个目录里,并且把位置返回给我们,同时还适合第三方字体,svg之类的
options: {
name: '[name]_[hash].[ext]',
// name 是打包前模块的名称,ext是打包前的模块格式 team_哈希值.jpg
outputPath: 'images/',
//图片打包后存放目录
limit: 2048
//如果小于 2048 2KB的图片,会被转成base64位格式图片
}
}
},
{ // 打包的css它会在 index.html head标签 的style中
test: /.css$/,
use: ['style-loader','css-loader','postcss-loader']
},
{
test: /.s[ac]ss$/i,
// loader 是有执行顺序的,从后往前
use: ['style-loader','css-loader','sass-loader']
}
]
}
}
- 新建postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]
// 只有下面 安装 autoprefixer,这里才能require进去
}
- 安装 autoprefixer
- npm install autoprefixer -D
- autoprefixer是与时俱进的,transform: translate(100px,100px); 这个就不需要在添加浏览器前缀了;
11、Plugins
- plugin 可以在webpack运行到某个阶段的时候,帮你做一些事情,类似于生命周期的概念
- 拓展插件,在webpack构建流程中的特定时机注入扩展逻辑来改变构建结果或你想要的事情
- Html | WebpackPlugin
- Html |Webpckplugin 会在打包结束后,自动生成一个html文件,并把打包生成的js模块映入到该html文件中
11-1 个性化配置
- npm install -D html-webpack-plugin
- 配置
title: 用来生成页面的 title 元素
filename: 输出的 HTML 文件名,默认是 index.html, 也可以直接配置带有子目录。
template: 模板文件路径,支持加载器,比如 html!./index.html
inject: true | 'head' | 'body' | false ,注入所有的资源到特定的 template 或者 templateContent 中,如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body 元素的底部,'head' 将放置到 head 元素中。
favicon: 添加特定的 favicon 路径到输出的 HTML 文件中。
minify: {} | false , 传递 html-minifier 选项给 minify 输出
hash: true | false, 如果为 true, 将添加一个唯一的 webpack 编译 hash 到所有包含的脚本和 CSS 文件,对于解除 cache 很有用。
cache: true | false,如果为 true, 这是默认值,仅仅在文件修改之后才会发布文件。
showErrors: true | false, 如果为 true, 这是默认值,错误信息会写入到 HTML 页面中
chunks: 允许只添加某些块 (比如,仅仅 unit test 块)
chunksSortMode: 允许控制块在添加到页面之前的排序方式,支持的值:'none' | 'default' | {function}-default:'auto'
excludeChunks: 允许跳过某些块,(比如,跳过单元测试的块)
// 插件 个性化配置
plugins: [
new HtmlWebpackPlugin({
title: '标题自定义',//标题
template: './index.html', //模板源文件
filename: 'index.html' // 输出的HTML文件名,默认是index.html 可修改
})
]
- 模板index.html title 这里要小写,看官方文档即可
- <%= htmlWebpackPlugin.options.title %>
11-2 删除冗余文件
- 每次打包前,由于我前面打包生产力 build文件夹目录里面会有冗余文件,我想把之前的build文件夹目录删除
- clean-webpack-plugin
- npm install --save--dev clean-webpack-plugin
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
// 打包入口文件
mode:'development',
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, ' build'),
filename: 'index.js'
},
//处理模块
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.(png|jpe?g|gif)$/,
// 不光可以处理图片,还可以处理 视频,音频,只要后缀格式正确
rules: [
{
test:/.(png|jpe?g|gif)$/,
use: {
// url-loader 可以限定模块体积,根据体积判断是否需要转换成base64,减少http请求
loader: 'url-loader', // file-loader就是把模块,放在另外一个目录里,并且把位置返回给我们,同时还适合第三方字体,svg之类的
options: {
// name 是打包前模块的名称,ext是打包前的模块格式
name: '[name]_[hash].[ext]',//team_哈希值.jpg
outputPath: 'images/', //图片打包后存放目录
limit: 2048 //如果小于 2048 2KB的图片,会被转成base64位格式图片
}
}
},
{ // 打包的css它会在 index.html head标签 的style中
test: /.css$/,
use: ['style-loader','css-loader','postcss-loader']
},
{
test: /.s[ac]ss$/i,
// loader 是有执行顺序的,从后往前
use: ['style-loader','css-loader','sass-loader']
}
]
},
// 插件 个性化配置
plugins: [
new HtmlWebpackPlugin({
title: '标题自定义',//标题
template: './index.html', //模板源文件
filename: 'index.html' // 输出的HTML文件名,默认是index.html 可修改
}),
//在打包之前,先帮我们把生成目录删除一次
new CleanWebpackPlugin()
]
}
11-3 CSS文件不想以style方式放在html头部,而是以CSS文件方式打包
- mini-css-extract-plugin
- npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
{
test: /.css$/,
use:[MiniCssExtractPlugin.loader, 'css-loader']
}
new MiniCssExtractPlugin({
filename: '[name].css'
})
12、sourceMap
- 最大的好处,快速定位问题
- 源代码与打包后的代码映射关系
- 在dev模式中,默认开启,关闭的化,可以在配置文件里
devtool: 'none' // 默认none
devtool: 'source-map',//代码打包后的代码映射,代码哪里有问题,报错,可在控制台直观看到
- devtool:"cheap-module-eval-source-map" //开发环境
- devtool:"cheap-module-source-map" // 线上环境
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// 打包入口文件
mode:'development',
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, ' build'),
filename: 'index.js'
},
devtool: 'none',//source-map//代码打包后的代码映射
//处理模块
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.(png|jpe?g|gif)$/,
// 不光可以处理图片,还可以处理 视频,音频,只要后缀格式正确
rules: [
{
test:/.(png|jpe?g|gif)$/,
use: {
// url-loader 可以限定模块体积,根据体积判断是否需要转换成base64,减少http请求
loader: 'url-loader', // file-loader就是把模块,放在另外一个目录里,并且把位置返回给我们,同时还适合第三方字体,svg之类的
options: {
// name 是打包前模块的名称,ext是打包前的模块格式
name: '[name]_[hash].[ext]',//team_哈希值.jpg
outputPath: 'images/', //图片打包后存放目录
limit: 2048 //如果小于 2048 2KB的图片,会被转成base64位格式图片
}
}
},
{ // 打包的css它会在 index.html head标签 的style中
test: /.css$/,
use: [MiniCssExtractPlugin.loader,'css-loader','postcss-loader']
},
{
test: /.s[ac]ss$/i,
// loader 是有执行顺序的,从后往前
use: ['style-loader','css-loader','sass-loader']
}
]
},
// 插件 个性化配置
plugins: [
new HtmlWebpackPlugin({
title: '标题自定义',//标题
template: './index.html', //模板源文件
filename: 'index.html' // 输出的HTML文件名,默认是index.html 可修改
}),
//在打包之前,先帮我们把生成目录删除一次
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
})
]
}
13、WebpackDevServer
- 提升开发效率的利器,它除了图片,它把所有文件,都放在了内存中
- 每次改完代码都需要重新打包一次,打开浏览器,刷新一次,很麻烦
- 我们可以安装使用webpackdevserver来改善这块的体验
- npm install webpack-dev-server -D
devServer: {
contentBase: './build', //目录
open: true, // 打开历览器
port: 8080 //设置端口号
}
13-1:跨域,自己mock数据 使用expres
- npm install express -D
- 新建一个server.js
const express = require('express')
const app = express();
const port = 9090
app.get('/api/info',(req,res)=>{
res.json({
name: '疾风剑豪',
age: 25,
msg: '快乐风男,面对疾风吧!'
})
})
app.listen(port);
console.log(`服务器启动成功端口号:${port}`)
- webpack.config.js配置代理
devServer: {
contentBase: './build', //目录
open: true, // 打开历览器
port: 8080, //设置端口号
proxy:{
"/api": {
target: "http://localhost:9090"
//配置完跨域以后,切记,前端页面也要重启,不然你会发现 它一直走 8080端口请求 api
}
}
}
14、Hot Module Replacement(HMR:热模块替换)
- 使用vueCli创建项目时,会发现我们修改某个值时,页面没有刷新,但是被修改的值,已经更新在页面中了
- 这玩意时webpack 自带的,不需要额外安装
- 启动hmr 需要引入webpack 在index.js中
- const webpack = requrie('webpack')
14-1:处理CSS
- index.js
import './index.css'
var btn = document.createElement('button');
btn.innerHTML = '添加一个DIV'
document.body.appendChild(btn);
btn.onclick = function (){
var div = document.createElement('div');
console.log(1);
div.innerHTML = 'item';
document.body.appendChild(div);
}
- webpack.config.js
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// 打包入口文件
mode:'development',
entry: './index.js',
// 打包后文件,path输出目录名 可以修改 ;filename打包生成的js文件名 默认main.js 可修改
output: {
// 公共路径 ,例如CDN 这种
//publicPath:'',
path: path.resolve(__dirname, 'build'),
filename: 'index.js'
},
devtool: 'cheap-module-eval-source-map',//source-map//代码打包后的代码映射
//处理模块
module: {
//遇到不认识的模块,这里写,找 loader 解决
// file-loader 专门用来 处理 静态文件的,使用前 必先安装
// npm install file-loader -D
// test:/.(png|jpe?g|gif)$/,
// 不光可以处理图片,还可以处理 视频,音频,只要后缀格式正确
rules: [
{
test:/.(png|jpe?g|gif)$/,
use: {
// url-loader 可以限定模块体积,根据体积判断是否需要转换成base64,减少http请求
loader: 'url-loader', // file-loader就是把模块,放在另外一个目录里,并且把位置返回给我们,同时还适合第三方字体,svg之类的
options: {
// name 是打包前模块的名称,ext是打包前的模块格式
name: '[name]_[hash].[ext]',//team_哈希值.jpg
outputPath: 'images/', //图片打包后存放目录
limit: 2048 //如果小于 2048 2KB的图片,会被转成base64位格式图片
}
}
},
{ // 打包的css它会在 index.html head标签 的style中
test: /.css$/,
// use: [MiniCssExtractPlugin.loader,'css-loader','postcss-loader']
use: ['style-loader','css-loader','postcss-loader']
},
{
test: /.s[ac]ss$/i,
// loader 是有执行顺序的,从后往前
use: ['style-loader','css-loader','sass-loader']
}
]
},
// 插件 个性化配置
plugins: [
new HtmlWebpackPlugin({
title: '标题自定义',//标题
template: './index.html', //模板源文件
filename: 'index.html', // 输出的HTML文件名,默认是index.html 可修改
favicon: path.resolve('./favicon.ico'), // 网页icon图标
inject: true
}),
//在打包之前,先帮我们把生成目录删除一次
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new webpack.HotModuleReplacementPlugin(),
],
devServer: {
contentBase: './build', //目录
open: true, // 打开历览器
port: 8080, //设置端口号
hot: true,
hotOnly: true,
proxy:{
"/api": {
target: "http://localhost:9090"
//配置完跨域以后,切记,前端页面也要重启,不然你会发现 它一直走 8080端口请求 api
}
}
}
}
14-2:处理JS
- a.js
function a(){
var div = document.createElement('div');
div.setAttribute('id','number');
div.innerHTML = 100000;
document.body.appendChild(div);
}
export default a;
- b.js
function b(){
var div = document.createElement('div');
div.setAttribute('id','counter');
div.innerHTML = 1;
div.onclick = function (){
div.innerHTML = parseInt(div.innerHTML,10) +1
}
document.body.appendChild(div);
}
export default b;
- webpack.config.js
devServer: {
contentBase: './build', //目录
open: true, // 打开历览器
port: 8080, //设置端口号
hot: true,
// 即便HMR不生效,浏览器页不自动刷新,就开启hotOnly
hotOnly: false
// 我这里 hotOnly 设置为false的时候,浏览器会自动刷新一次
}
- index.js
import a from './a'
import b from './b';
a();
b();
if (module.hot) {
//监听,我们传入的文件
module.hot.accept('./a.js',()=>{
// 监听我们传入的方法,同时有个回调函数,事先移出,以前加添过的id,在重新执行移出,方法。完成了 数据修改保持,热更新。
console.log('数据更新');
document.body.removeChild(document.getElementById('number'))
a();
})
}
//HMR 默认对css支持较好,对js模块需要额外处理,通过module.hot.accep来对需要更新的模块进行监控
15、Babel
- 1、npm install -D babel-loader @babel/core
{
test: /.js$/i,
use: {loader: "babel-loader"}
}
- 2、npm install @babel/preset-env -D 语法转换规则
- 3、npm install @babel/polyfill 以全局变量来的方式注入进来的。windows.Promise,会造成全局对象的污染
- index.js
import '@babel/polyfill'
//引入,但是你会发现,打包后的文件体积大到900KB,下面介绍如何 按需打包,如果我只用了Promise
let obj = {};
const str = '';
const arr = [new Promise(()=>{}),new Promise(()=>{})];
arr.map(item=>{
console.log(item);
})
- index.js 移出引入的 import '@babel/polyfill'
- polyfill 的按需加载,提升打包速度与包体积,还可以兼容低版本的浏览器
{
test: /.js$/i,
exclude:/node_modules/, //排除 这个目录下的JS模块
use: {
loader: "babel-loader",
options: {
presets: [[
"@babel/preset-env",
{
useBuiltIns: 'usage',//按需加载
corejs: 2,
}
]]
}
}
}
- @bael/plugin-transform-runtime 对比polyfill来说,它不会造成全局污染
- npm install --save @babel/runtime