现在的前端,一定都用过Vue或者React,多多少少都有接触过webpack,我还清楚地记得第一次看Vue的Webpack配置时,仿佛在看天书通常。webpack做为前端工程化的核心知识之一,由于其功能太多,配置项又多又杂,初学时也比较难啃。css
这是一个面向初学者的webpack系列博文。从0开始,一步步搭建出完整的、适用于常规环境的webpack配置。html
每章都以树状结构扩深知识点,尽量的涵盖更多更深的知识内容,同时保留每一个章节的全部代码。前端
首先建立一个文件,而后执行 npm init
webpack
随后建立对应子文件夹git
.webpackLemo // 文件夹
│
│-- config // 存放配置文件
│
│-- public // 存放模板
│
│-- src // 存放入口文件
│
└─- package.json
复制代码
咱们有了基本文件夹,接下来开始构建最基本配置,能知足平时写demo用。github
首先安装webpack工具库web
npm i webpack webpack-cli
算法
建立入口文件npm
// src/index.js
console.log("Webpack Lemo");
复制代码
// public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webpack Lemo</title>
</head>
<body>
<script src="./main.js"></script> //打包后的文件为 main.js 在这里手动写入
</body>
</html>
复制代码
建立配置文件json
// config/webpack.config.js
const path = require('path');
module.exports = {
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, '../build')
}
}
复制代码
entry :入口起点配置。简单来讲,由html直接引用的文件称为入口起点,从这个起点开始,应用程序启动执行。例子中的
main
为入口起点的 [name] 值output:输出配置。webpack打包完成,怎么输出,要输出哪些文件,输出到哪等相关信息的配置
output.path
要求接受一个绝对路径。path.resolve
方法会把一个路径或路径片断的序列解析为一个绝对路径,__dirname
指向当前文件的路径entry 配置里使用的是相对路径,这个路径默认指向代码被执行时路径,即 webpackLemo 文件夹的根目录。可经过设置 context 来修改路径上下文。
// 与正文中的配置效果等同 { context: path.resolve(__dirname), entry: { main: '../src/index.js' } } 复制代码
// package.json
{
...
"scripts": {
"dev": "webpack --config ./config/webpack.config.js"
},
...
}
复制代码
接下来只需在命令行里执行 npm run dev
就能进行第一次打包
先忽视 warning ,能够看见webpack自动打包了 src
目录下的文件,在根目录下自动生成build文件,并将打包后的入口文件命名为 main.js 放入build文件中。
而后咱们能够把 public 目录下的 index.html 手动复制到 build 目录下。
完成以上操做后,咱们的目录会长成这样
.webpackLemo
│
│-- build // 存放打包后的文件
│ │-- main.js // src/index.js打包生成的文件
│ │-- index.html // 从public中手动复制
│
│-- config
│ │-- webpack.config.js // 新建webpack配置文件
│
│-- public
│ │-- index.html // 新建html模板文件
│
│-- src
│ │-- index.js // 新建入口文件
│
└─- package.json
复制代码
用浏览器打开 ./build/index.html,能够看见控制台里输出了 在 ./src/index.js 里写的 console.log信息
若是每次打包,都须要咱们手动粘贴一次 index.html,那也太麻烦了。若是有一个哥们儿能 帮咱们自动复制index.html文件,而且在index.html中自动引入咱们打包后的文件 那就行了。
这个哥们儿叫作 html-webpack-plugin 。
执行安装 npm i html-webpack-plugin
而后修改文件
// public/index.html
<!DOCTYPE html>
<html lang="en">
...
<body>
// <script src="./main.js"></script> // 删除手动写入的 对main.js的引用
</body>
</html>
复制代码
// config/webpack.config.js
...
// 引入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
output: {
...
filename: '[name].bundle.js', // 添加filename配置
},
plugins: [ // 注意是个数组
new HtmlWebpackPlugin({ // 在plugin中使用 html-webpack-plugin
template: './public/index.html' // 配置模板项地址
}),
]
}
复制代码
plugins:配置webpack插件的地方
filename 配置项中使用了[name],这里的[name]为输出的模块名。除了[name],webpack还提供了别的模板语法,可在这里找到全部信息 output.filename
如今咱们再执行 npm run dev
能够看见此次打包生成的文件名为main.bundle.js,而且 build 目录下的index.html 文件里自动引入了 main.bundle.js
完成以上操做后,咱们的目录会长成这样
.webpackLemo
│
│-- build
│ │-- main.js // 第一次打包生成的文件
│ │-- main.bundle.js // 第二次打包生成的文件
│ │-- index.html // 使用 html-webpack-plugin 后生成的html文件
│
...
复制代码
能够看见第二次打包时,咱们修改了输出配置,生成了新的文件,可是第一次打包的内容仍是被保留了下来。其实第一次打包的内容已经用不上了,有没有什么哥们儿能帮咱们自动删除不须要的内容?
有,这个哥们儿叫作 clean-webpack-plugin
执行安装 npm i clean-webpack-plugin
而后修改文件
// config/webpack.config.js
...
// 引入clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
...
output: {
path: path.resolve(__dirname, '../build'),
filename: '[name].[contenthash].js', // 咱们再修改一次输出文件名
},
plugins: [
...
new CleanWebpackPlugin(); // 使用 clean-webpack-plugin
]
}
复制代码
如今咱们第三次执行 npm run dev
,能够看见build目录下头两次生成的入口文件都被清除了,只保留了第三次生成的内容。
完成以上操做后,咱们的目录就长成这样
.webpackLemo
│
│-- build
│ │-- main.417cd68a8235c5cd4f89.js // 第三次打包生成的文件
│ │-- index.html
│
...
复制代码
到目前为止,已经支持了基本功能打包,下一步来处理css样式和file文件
对css文件的处理有2种方式:
将css代码以 <style>
标签的形式嵌入 html 中
生成css文件,以 <link>
标签的形式在 html 中引入
这里咱们只讨论第一种形式,第二种会在 代码分割(卫星) 中介绍
咱们须要4个插件
<style>
标签的形式嵌入 html 中loader和plugin的区别 :
// 官方文档原文 While loaders are used to transform certain types of modules, plugins can be leveraged to perform a wider range of tasks like bundle optimization, asset management and injection of environment variables. // 渣译 loader通常用来转换某些类型的modules,而插件能够用来执行更普遍的任务,例如对包的优化、资源管理、环境注入等 // 大白话 loader是一个转换器,将A文件进行编译成B文件,好比:将A.less转换为A.css,单纯的文件转换过程。 plugin是一个扩展器,丰富了webpack自己,针对是loader结束后,webpack打包的整个过程,它并不直接操做文件,而是基于事件机制工做,会监听webpack打包过程当中的某些节点,执行普遍的任务 复制代码
执行安装 npm i style-loader css-loader postcss-loader autoprefixer
而后修改文件
// ./config/webpack.config.js
...
module.exports = {
...
module: { // 这里是对象
rules: [ // 这里是数组
{ // 数组中的每一个具体配置
test: /\.css$/, // 匹配 .css文件
use: [ // 当匹配上 .css 文件后,会依次使用loader进行处理
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
}
]
}
]
}
}
复制代码
module:各类模块应该如何处理,由module进行配置
loader的处理顺序为从下到上。正文中loader处理顺序为:postcss-loader、css-loader、style-loader
// ./src/index.js
import './index.css'
...
复制代码
// ./src/index.css
body {
width: 100%;
height: 200px;
background-image: linear-gradient(to right, red , yellow);
}
复制代码
// ./package.json
{
...
"browserslist": [
"iOS >= 6",
"Android >= 4",
"IE >= 9"
]
}
复制代码
browserslist 用来配置 咱们的应用会在哪些平台、哪些浏览器和浏览器版本上使用。 autoprefixer 会读取该项值,用来以为须要添加哪些前缀,若是运行在最新的浏览器上,也许不会添加相应的前置信息
browserslist 默认值:> 0.5%, last 2 versions, Firefox ESR, not dead
如今执行 npm run dev
,build 目录里没有新增 .css文件,用浏览器打开 ./build/index.html 文件,能够看见背景有个渐变色,从控制台里能够看见样式代码以 <style>
标签的形式嵌入到了html中,而且自带了厂商前缀
完成以上操做后,咱们的目录就长成这样
.webpackLemo
│
│-- src
│ │-- index.js
│ │-- index.css // 新增长的css代码
│
...
复制代码
less其实就是css的预处理器,一些代码里可能会用sass,可是原理相似,这里就用less举例
在上一节的基础上,额外安装一个 less-loader
处理less文件
执行安装 npm i less-loader
而后修改文件
// ./config/webpack.config.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader', // 只增长一行less-loader 处理less文件
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
}
]
}
]
}
}
复制代码
// ./src/index.js
import './index.less' // 引入less文件
...
复制代码
// ./src/index.less
body {
width: 100%;
height: 200px;
background-image: linear-gradient(to right, red , yellow);
}
复制代码
执行 npm run dev
,获得的效果和处理css同样
完成以上操做后,咱们的目录就长成这样
.webpackLemo
│
│-- src
│ │-- index.js
│ │-- index.css
│ │-- index.less
│
...
复制代码
其实只要是文件,均可以处理,这里用图片文件举例
可用2种 loader 进行处理
这两个loader做用比较相似,最大的区别在于 file-loader 会生成文件, url-loader 会把文件数据压缩成base64直接使用,不会生成文件。二者能一块儿使用,在某些场景下比使用单一loader效果更好,可参考 这篇博文(卫星)
这里我用file-loader举例
执行安装 npm i file-loader
而后修改文件
// ./config/webpack.config.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
}
复制代码
// ./src/index.js
...
import img from '../statics/imgs/img.jpg'
const myimg = new Image();
myimg.src = img;
document.body.appendChild(myimg);
...
复制代码
执行 npm run dev
,能够看见build文件里增长了打包后的图片文件,打开 ./build/index.html 后也能看到相应的图片被挂载到页面上
完成以上操做后,咱们的目录就长成这样
.webpackLemo
│
│-- build
│ │-- 051fa5032109fbc8005c856a48cf1c52.jpg
│ │-- index.html
│ │-- main.a14556a5d43741e69cdd.js
│
│-- statics // 存放静态资源
│ │-- imgs // 存放图片
│ │ │-- img.jpg
│
...
复制代码
到如今,咱们已经支持css打包和文件打包,本身写demo时,使用这样的webpack配置已经OK了,可是我每次改了代码都要从新执行一次 npm run dev
,真的太麻烦,若是能让webpack自动刷新页面就行了。
让咱们来构建一个开发环境,让咱们每次更新的时候,webpack能自动帮咱们打包,而且能实时刷新页面.
要能实现实时刷新页面,webpack提供了3种能力
这里咱们采用 webpack-dev-server
执行安装 npm i webpack-dev-server
而后修改文件
// ./config/webpack.config.js
...
module.exports = {
mode: 'development', // 设置mode为'development'模式
devtool: 'cheap-module-eval-source-map', // 设置source-map
devServer: {
contentBase: './build',
open: true
},
...
}
复制代码
mode:至关于设置一套预设优化配置,默认为
none
。详细可查看 官网文档devtool:用于配置source-map,用来加强调试能力,不一样的值会影响构建和重构建的速度。 详细可查看 官方文档
// package.json
{
...
"scripts": {
// 把dev改为build
"build": "webpack --config ./config/webpack.config.js",
// 这里改为dev,并使用新命令项
"dev": "webpack-dev-server --config ./config/webpack.config.js"
},
...
}
复制代码
接下来执行 npm run dev
,webpack帮咱们启动了一个端口号为8080的服务器,并自动打开了浏览器,咱们修改代码,能自动帮咱们打包新代码,并刷新页面。
到这里,一个能打包、能处理css、处理文件、自启服务器、修改代码后能自动打包,自动刷新页面的配置就完成了。这样一个简单的配置已经实现我的写demo的需求,例如跑跑算法代码,测试一段代码的输出等等。
本章使用:
库
webpack、webpack-cli
webpack工具库webpack-dev-server
webpack web-serverloader
file-loader
解析经过模块化方式引入的文件,输出成文件url-loader
(非必要) 经过模块化方式引入的文件,以base64的形式输出style-loader
将css代码以 <style>
标签的形式嵌入 html 中css-loader
解析经过模块化引入的css文件postcss-loader
提供预处理css的一些能力,拥有许多子插件,提供了许多能力less-loader
(非必要) 解析less代码文件plugins
clean-webpack-plugin
每次打包能清空打包文件夹里以前的内容html-webpack-plugin
能自动生成Html文件,并自动引入打包生成的js文件autoprefix
postcss-loader的子插件,提供厂商前缀自动补全能力,如 -m-本章节代码仓库:代码仓库
本章节Github-blog: Github-blog
若是文中有错误/不足/须要改进/能够优化的地方,但愿能在评论里友善提出,做者看到后会在第一时间里处理
若是你喜欢这篇文章,👍点个赞再走吧,github的星星⭐是对做者持续创做的支持❤️️