「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」css
众所周知,在前端工程化日趋复杂的今天,模块化打包工具在咱们的平常开发中起着愈来愈重要的做用,而其中, webpack
已然是前端打包构建的不二选择。html
说到 webpack
,可能不少小伙伴会以为既熟悉又陌生,熟悉是由于在咱们开发的每个项目中,都会使用到它。而陌生在于, webpack
有着复杂的配置和五花八门的功能而感到陌生。前端
所以,咱们有时候会被这复杂的配置先吓到,从而被劝退学习。vue
然而,在技术更新迭代这么快的一个大环境下, webpack
仍是很值得咱们去学习的。node
在下面的这篇文章中,将讲解 webpack
的入门核心概念。一块儿来学习吧~🎬webpack
当咱们要写一个网页时,首先咱们会先建立一个 index.html
文件,以后在可能还会有一些 js
文件,那么咱们就会在 html
文件中,引入这些 js
文件。web
试想一下,若是 js
文件不少,而后咱们一个个引入,这样若是遇到报错了呢?会不会就很难定位到是哪一个文件错了,这样就会使得开发效率很是低下了。面试
所以,就有了 webpack
。 webpack
会将咱们所写的代码,进行一个翻译,并将翻译完的内容,进行一个模块化的打包,使得项目变得工程化。正则表达式
接下来,咱们就来说解, webpack
到底是什么以及怎么安装使用。express
webpack
有时候会被误认为是一个 js
的翻译器,但其实 webpack
称不上是一个 js
的翻译器。
由于它只认识 import
这样相似的语句,而不认识其余的 js
高级语法。因此若是称它是一个 js
的翻译器,其实是咱们高看了它。
查看官方的定义咱们能够发现, webpack
是一个模块打包工具,同时 webpack
也能够支持 commonjs
的模块打包规范。
然而,随着时间的推移和技术的不断更新, webpack
再也不是只会打包 js
的模块打包工具, webpack
如今还支持 css文件
、 jpg
、 png
等各类文件的打包。
webpack
是基于 nodejs
开发的模块打包工具,本质上是由 node
实现的。所以咱们要先安装本机的 node
环境。这里附上官方网站的连接,建议你们下载稳定版本
以后查询本机的 node
和 npm
版本,查看是否安装成功。
node -v
npm -v
复制代码
先建立一个项目,假设命名为 webpack-demo
。以后在该项目下经过如下命令建立一个文件夹:
mkdir webpack-demo
复制代码
进入 webpack-demo
文件,初始化项目。命令行以下:
cd webpack-demo
npm init 或 npm init -y //加-y表示默认自动配置项
复制代码
以后一路 Enter
回车便可。
你们能够看到项目结构,以上操做就是在 webpack-demo
文件下建立了一个 package.json
文件,以后咱们把 package.json
文件的内进行改造。具体代码以下:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
//将这个项目设置为私有
"private":true,
//"main": "index.js", //去掉入口文件
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
//写上做者名
"author": "Monday",
//保持项目私有
"license": "ISC"
}
复制代码
第一种方式:全局安装
npm install webpack webpack-cli -g
复制代码
第二种方式:当前项目下安装
npm install webpack webpack-cli -D
复制代码
在这里的建议是选择第二种方式进行安装。那为何呢?是由于全局安装 webpack
有什么问题吗?
事实上,全局安装只会安装一个版本。
那么假如咱们如今要跑两个项目,而且这两个项目出现原先安装的 webpack
版本不同,安装低版本 webpack
的项目,就有可能会致使在咱们的本机中运行不起来。因此建议是使用第二种方式进行安装。
安装完成以后,咱们还要来查询当前使用的 webpack
版本号,以确保咱们是否已经安装成功。具体命令行以下:
npx webpack -v
复制代码
这个时候就有小伙伴会有疑问说,为何前面还要加个 npx
才能查找版本号。
缘由在于,咱们只在当前项目中安装,因此 webpack
这个命令在全局中并无找到。而 node
提供了 npx
,这个时候 npx
就能够找到咱们所运行项目目录下的 node-module
中的 webpack
安装包,因此这种方式是把咱们的 webpack
安装在咱们的项目内,而后经过 npx
去运行 webpack
就能够了。
若是咱们想要安装具体版本号的 webpack
,那么咱们先查看 webpack
的版本号信息。命令以下:
npm info webpack
复制代码
查到具体版本号之后,使用如下命令进行安装:
npm install webpack@4.16.5 webpack-cli -D //4.16.5表示版本号
复制代码
不少时候,咱们还没写配置文件,项目就成功跑起来了。这并非由于不用写,而是 webpack
团队提早帮咱们写好了不少默认的配置文件,使得咱们在运行项目时不用进行过多的配置就能够达到咱们的使用需求。那下面,就跟着你们一块儿来写一个配置文件。
咱们先来了解下项目结构,在咱们建立完项目时,咱们的源代码通常放在 src
文件夹下,而且打包后的文件通常放在 dist
文件下,同时 webpack
的配置文件命名为 webpack.config.js
,而且放在项目的根目录下。
├── dist 放置打包后的文件
├── src 放置项目源代码
├── webpack.config.js webpack配置文件
├── package-lock.json
├── package.json
复制代码
看完项目结构,咱们来了解一下 webpack
的配置文件具体须要怎么配置。具体代码以下:
//node的核心模块
const path = require('path');
module.exports = {
//设置为development时,代码不会进行压缩;设置为production时,代码会进行压缩。
mode:'production',
// 放置入口文件,明确怎么打包,要打包哪个文件
entry: './src/index.js',
//entry: {
// main: './src/index.js'
//},
// 输出,代表webpack应该怎么输出,输出到哪一个地方
output: {
filename: 'bundle.js',
// 指打包后的文件要放在哪一个文件下
// __dirname表示该项目的根目录
path: path.resolve(__dirname, 'dist')
}
}
复制代码
了解完基本配置,此时可能有小伙伴内心有一个疑惑, webpack
配置文件的命名必定要命名为 webpack.config.js
吗,是否能够命名为其余的呢?
答案是确定能够的,不过咱们须要进行一个特殊处理。日常若是咱们命名为 webpack.config.js
时,能够直接使用 npm webpack
来跑咱们的项目。若是不用这个命名时,假设命名为 webpackconfig.js
,那么咱们能够经过如下命令行,来打包咱们具体的项目。
npx webpack --config webpackconfig.js
复制代码
以上命令行的意思为:指让 webpack
来帮咱们打包,具体打包哪个文件呢?以 webpackconfig.js
为配置文件,来帮咱们打包。
看完上面的内容,相信小伙伴们对 webpack
有了一个基础的认识。
那试想如下,常常要使用 npx webpack
来帮咱们打包文件,这样是否是会有点略显麻烦呢?
因此,咱们来再了解一个内容:使用 npm script
来简化咱们的打包代码。
在咱们的项目根目录下,会有一个 package.json
文件,这个文件的代码以下:
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Monday",
"license": "ISC",
"devDependencies": {
"webpack": "^5.39.1",
"webpack-cli": "^4.7.2"
}
}
复制代码
你们定位到scripts部分,接下来,咱们把script部分进行一个改造。具体代码以下:
"scripts": {
/* webpack 会先到node_module下面进行打包*/
"bundle": "webpack"
},
复制代码
改造完成之后,咱们就至关于在 package.json
里面配置了一个 npm script
,上面的代码意思为这个 script
对应的名字叫作 bundle
,以后呢, bundle
的底层会帮助咱们执行 webpack
,并进行打包。
这么编写以后,咱们就再也不须要使用 npx webpack
来作运行 webpack
,而是使用 npm run bundle
来作命令进行打包。
讲解完上面的内容,咱们来对 webpack
打包之后控制台的一些输出内容进行概括总结。
输出内容 | 具体含义 |
---|---|
hash | 表明本次打包对应的惟一哈希值 |
version | 表明这次打包使用的webpack的版本 |
time | 当前项目总体打包的具体耗时 |
assets | 打包后的文件具体是哪个,好比:bundle.js |
size | 打包后文件的大小 |
chunks | 放置本身对应文件的id值以及对应文件所引入其余文件的id值 |
chunk Names | 对应entry配置的main |
Webpack
默认是知道如何打包 js
模块的,可是它不知道 jpg
这种文件该怎么打包。
这个时候咱们须要在 webpack.config.js
文件下作配置,配置 file-loader
。咱们在配置中增长一个新的 module
。具体代码以下:
module:{
rules:[{
test:/\.jpg$/,
use:{
loader:'file-loader'
}
}]
}
复制代码
接下来咱们来正向分析下 webpack
是如何打包 jpg
这种静态文件的。
首先 webpack
会进入src
目录, new
一个 index.js
文件,那么如今咱们要对这个文件进行打包。
因此,我在命令行里,运行了 npm run bundle
。当你运行 npm run bundle
时,实际上在执行的是 package.json
里面的 script
,这个 script
帮咱们运行 webpack
,而后呢, webpack
帮咱们作打包。这个时候 webpack
就会去找它相对应的配置,根据这个配置帮咱们作打包。
那么咱们来看一下,若是咱们遇到的是 js
文件,那么 webpack
默认会进行打包。可是呢?若是遇到的是一张 jpg
的图片呢? webpack
这个时候就懵了, webpack
并不认识 jpg
这种格式的代码。
所以,咱们就能够引用一个模块module,来帮咱们打包。这个模块叫 file-loader
,file-loader
这个 loader
就能够帮助咱们完成打包的过程。
那么实际上, file-loader
的底层,帮咱们作了什么事情呢?
当咱们打包 jpg
文件时, webpack
会把 jpg
文件移动到 dist
文件下,而且对 jpg
文件赋予一个新的名称。而后呢,它会把这个名称做为一个返回值,返回给咱们引入模块的变量之中。
这就是 file-loader
底层处理打包文件的一个流程。
固然。 file-loader
不只仅能够处理 jpg
这样的文件图片。理论上,它还能够处理不少种类型的静态资源。
阐述了 file-loader
以后,相信你们对 loader
有了一个基础认识。那么咱们如今就来对loader的基础定义进行梳理。具体以下:
自己 webpack
对于一些文件是不知道如何处理的,可是 loader
知道。因此呢,当遇到一些 非js
文件时,通常去求助于 loader
就能够了。所以咱们就须要让 webpack
去求助 loader
模块,来识别出 非js
的文件。
引用 webpack
官方中文文档的一句话,文档中说到: webpack
只能理解 JavaScript
和 JSON
文件,这是 webpack
开箱可用的自带能力。loader 让 webpack
可以去处理其余类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。本质上, loader
是导出为函数的 JavaScript
模块。
若是咱们如今要对打包后的图片进行自定义命名,那该怎么作呢?
咱们在 webpack.config.js
文件下的 module
再进行改进。具体代码以下:
module:{
rules:[{
test:/\.jpg$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]'
}
}
}]
}
复制代码
经过配置 options
,就能够达到图片自定义命名的效果。
假设咱们如今不局限于打包 jpg
文件,还想要打包其余的图片文件。那么咱们能够这样配置:
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]'
}
}
}]
}
复制代码
经过正则表达式的方式,来增长新的图片类型。
假设咱们如今想要把打包后的文件放到 image
文件下,那该怎么作呢?具体代码以下:
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]',
//将jpg、png和gif图片文件,指定到dist目录下的images文件下
outputPath: 'images/'
}
}
}]
}
复制代码
在使用了 file-loader
以后,咱们再来了解一个知识点: url-loader
。 url-loader
能够达到几近 file-loader
的效果。具体使用方法以下:
npm i url-loader -D
复制代码
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
}]
}
复制代码
咱们只要安装上 url-loader
,而且在配置中将 file-loader
替换为 url-loader
便可。
但值得注意的是,使用 url-loader
进行打包,会有一些须要注意的事项。
当你去打包一个 jpg
文件的时候,与 file-loader
不同的是, url-loader
会将图片转换成一个 base64
的字符串,而后直接放到咱们 dist
目录下的 bundle.js
里面,而不是单独生成一个图片文件。
好处就是,直接访问,而不用去文件夹下访问,节省了一次 http
请求。
而带来的坏处就是,若是这个 js
文件特别大,那么打包生成的js文件也将会特别大,随之加载这个 js
的时间就会很长。
因此, url-loader
的最佳使用方式是什么呢?
若是说咱们引入的图片很小,只有 1~2KB
等小的体积,那么这个图片以 base64
的形式打包到 js
文件里,是一个很好的选择,就没有必要让这么小的图片再去发一次 http
请求。
但假设这个图片很大的话,那么尽可能不要使用 url-loader
,而使用 file-loader
,把这个图片打包到dist目录下,不要打包到 bundle.js
里面。否则会使得 bundle.js
文件变得很大,使得加载时间变得很长,不利于维护。
还有一种方法就是,咱们能够直接在 url-loader
下再加一个配置: limit
。具体代码以下:
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
//20480=>20KB
limit: 20480
}
}
}]
}
复制代码
经过以上代码咱们能够知道,当使用 url-loader
时,咱们能够给其加一个 limit
属性。那么上面代码所要表达的意思就是,当图片文件大小大于 20KB
时,咱们使用 url-loader
打包。当大于 20KB
时,就将图片文件放到 dist
的 images
文件下。
好比说,咱们如今想要让一张图片的大小为 150*150
,那么咱们就须要写下样式来修改这张图片。那 webpack
如何打包 css
文件呢?
咱们可使用 css-loader
和 style-loader
来对文件进行打包。具体配置以下:
npm install sass-loader node-sass --save-dev
复制代码
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
},{
test:/\.css$/,
use:['style-loader', 'css-loader']
}]
}
复制代码
css-loader
会帮咱们分析出,几个 css
文件之间的关系,最终把一个 css
文件,合并成一个 css
。那 style-loader
的做用又是是什么呢?
在获得了 css-loader
生成的 css
文件以后, style-loader
会把这段内容挂载到页面的 head
部分,并将样式挂载到 head
中的 <style></style>
里面。
若是是要打包 sass
文件呢,则使用 sass-loader
、 style-loader
和 css-loader
这三个 loader
来对文件进行打包。具体配置以下:
npm install sass-loader node-sass --save-dev
复制代码
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
},{
test:/\.scss$/,
use:[
'style-loader',
'css-loader',
'sass-loader'
]
}]
}
复制代码
值得注意的是, loader
的执行顺序是从下到上,从右到左。
因此当咱们去执行一个 sass
文件时,首先会执行 sass-loader
,以后执行 css-loader
,最后才执行 style-loader
。
有时候咱们若是想要兼容多个浏览器时,那么咱们可能会在 css
文件里面添加 -webkit-
等厂商的前缀。可是呢,要知道 webpack
是没办法识别这些前缀的。这个时候咱们了解一个新的 loader
,就是 postcss-loader
,这个loader能够自动地帮咱们添加厂商前缀的信息。具体使用方式以下:
首先咱们先安装 postcss-loader
这个库,具体代码以下:
npm i postcss-loader -D
复制代码
安装完成以后,咱们在项目根目录下建立一个新的文件,名字叫 postcss.config.js
,以后对这个文件进行配置,代码以下:
首先安装 autoprefixer
:
npm install autoprefixer -D
复制代码
安装完成以后,如今咱们在 postcss.config.js
文件下来使用它,具体代码以下:
module.exports = {
Plugin:[
require('autoprefixer')
]
}
复制代码
接下来咱们在 webpack.config.js
文件下面,使用 postcss-loader
。具体代码以下:
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
},{
test:/\.scss$/,
use:[
'style-loader',
'css-loader',
'sass-loader',
'postcss-loader'
]
}]
}
复制代码
经过以上方式, webpack
就能够在帮咱们打包静态文件时,把对应的须要加入厂商前缀的样式给添加上前缀。
假设咱们如今想要给某一个 loader
增长配置项,好比说咱们要给 css-loader
增长配置项,那么咱们能够对代码进行以下处理。具体代码以下:
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
},{
test:/\.scss$/,
use:[
'style-loader',
{
loader: 'css-loader',
options: {
//代表前面要先走sass-loader和postcss-loader
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
}]
}
复制代码
从以上代码中咱们能够看到,当咱们想要给 css-loader
增长配置项时,那么再也不使用字符串的形式,咱们把字符串转化成一个对象。在对象里面,咱们填写相应的 loader
和 options
配置,这样就达到了咱们想要的需求。
有时候咱们在一个页面上,若是全局引入 css
,可能会很容易致使样式冲突问题。那这种状况该怎么处理呢?
为此咱们能够借助 css-loader
中的 modules
来实现 css
的模块化,旨在让引入的 css
文件拥有它独立的模块。那具体该怎么使用呢?
module:{
test:/\.scss$/,
use:[
'style-loader',
{
loader: 'css-loader',
options: {
//代表前面要先走sass-loader和postcss-loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}]
}
复制代码
从以上代码中咱们能够知道,经过 modules:true
语句,就能够开启 css
的模块化打包。开启以后,咱们就能够在各类文件下引入。引入方式以下:
import style from './index.scss';
var img = new Image();
img.src = bug;
img.classList.add(style.bug);
复制代码
从上述代码中咱们能够看到,开启 module
后,就能够为所欲为的引用该 css
中的内容啦!
有时候咱们在项目中有可能会遇到想要引入字体的问题,那 webpack
如何打包字体呢?具体代码以下:
module:{
rules:[{
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'file-loader',
}
}]
},
复制代码
经过以上代码咱们能够知道,跟 webpack
相关的静态文件格式为 eot、ttf和svg
等格式,因此须要须要把这几种类型引入。同时,跟其相关的 loader
为 file-loader
。
学完关于如何打包静态资源后,建议能够再用官方文档的相关部分来进行复习,具体连接戳~
在学习了如何使用 loader
来打包静态文件以后,接下来咱们一块儿来了解在 webpack
中,如何使用 plugins
让打包更便捷。
咱们在打包项目时, webpack
老是会把打包后的内容放到 dist
目录下。这个时候咱们可能还须要自行再去建立一个 index.html
来引入核心文件。那这样会不会就显得略有点麻烦了?
所以, webpack
给咱们提供了 plugin
插件来解决这个问题。
首先,咱们先来安装 plugin
,具体命令行以下:
npm install html-webpack-plugin -D
复制代码
接下来咱们将插件引入 webpack.config.js
当中,具体代码以下:
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [new HtmlWebpackPlugin({
//代表要引用哪个模板
template: 'src/index.html'
})]
复制代码
如今,咱们来梳理一下 htmlWebpackPlugin
如何帮咱们完成自动打包。
首先, htmlWebpackPlugin
会在打包结束后,自动生成一个 html
文件。以后呢,把打包生成的 js
文件自动引入到这个 html
文件中。
因此,从某种程度上来讲就是, plugin
能够在 webpack
运行到某个时刻的时候,自动地帮你作一些事情。即当咱们打包结束的这儿一时刻, plugin
会自动帮咱们建立 html
文件以供咱们直接使用。
有时候咱们有可能对 webpack.config.js
中的output所对应的filename进行修改,这就很容易致使在打包过程当中遇到多文件冲突。
那么咱们想要实现的就是,在打包时,先清空原来的dist文件夹,而后再生成一个新的dist文件夹。如何处理呢?请看下方。
首先咱们先安装依赖 clean-webpack-plugin
,具体命令行以下:
npm install clean-webpack-plugin -D
复制代码
接下来咱们将插件引入 webpack.config.js
当中,具体代码以下:
const CleanWebpackPlugin = require('clean-webpack-plugin');
plugins: [new HtmlWebpackPlugin({
//代表要引用哪个模板
template: 'src/index.html'
}),new CleanWebpackPlugin(['dist'])]
复制代码
经过以上代码,就能够在咱们项目打包时,先删除 dist
文件夹,以后再建立一个新的文件夹。
接下来咱们再来看 webpack
中的 entry
和 output
中几个比较核心的配置。
module.exports = {
mode:'development',
// 放置入口文件,明确怎么打包
entry:{
main: './src/index.js',
sub: './src/index.js'
},
plugins: [new HtmlWebpackPlugin({
//代表要引用哪个模板
template: 'src/index.html'
}),new CleanWebpackPlugin(['dist'])],
// 输出,代表webpack应该怎么输出
output: {
//若是把资源放在cdn下,则引入cdn
publicPath: 'http://cdn.com.cn',
//当entry有多个入口文件时,用[]能够输出多个文件
filename: '[name].js',
// 指打包后的文件要放在哪一个文件下
path: path.resolve(__dirname, 'dist')
}
}
复制代码
有时候,咱们在写代码时,总会莫名的出bug。看着控制台那红红的报错,内心总归很不是滋味。同时,若是咱们没有配置好 webpack
的话,那错误找起来简直是很恐怖的。
好比,在开发模式下,咱们默认 webpack.config.js
像下面这样配置,具体代码以下:
module.exports = {
mode:'development',
devtool: 'none',
entry:{
//打包到dist目录下的main.js
main: './src/index.js'
},
output: {
//用[]能够生成多个文件
filename: '[name].js',
// 指打包后的文件要放在哪一个文件下
path: path.resolve(__dirname, 'dist')
}
}
复制代码
而后呢,假设咱们如今代码里面错把 console.log
写成 consele.log
。那么如今控制台的打印效果以下:
你们能够看到,此时的错误定位到打包后的 main.js
文件里面的第96行。那试想一下,若是咱们的业务代码特别多,报错有可能就是在文件中的上前行了。
这样的场景并非咱们想看到的。咱们想作的事情呢就是,但愿 webpack
打包完成以后就把错误直接抛给咱们,并把其对应的具体文件地址显示出来。也就是咱们出错的那个代码文件,而不是打包后的文件 main.js
。
所以, webpack
给咱们提供了 sourceMap
这个配置,来解决这个问题。
咱们如今把 devtool
这个配置,改为 sourceMap
。具体代码以下:
module.exports = {
mode:'development',
devtool: 'source-map',
entry:{
//打包到dist目录下的main.js
main: './src/index.js'
},
output: {
//用[]能够生成多个文件
filename: '[name].js',
// 指打包后的文件要放在哪一个文件下
path: path.resolve(__dirname, 'dist')
}
}
复制代码
改完以后呢,咱们来看一下控制台的打印结果:
如今你们能够看到,改为 source-map
的配置以后,报错的定位直接到了咱们本身所编写代码的目录下,即 index.js
。而再也不是大海捞针似的在 main.js
里面找。
看完上面的例子以后,相信你们对 SourceMap
有了必定的了解。接下来咱们来看一下 sourceMap
的一些常见配置。具体看看下方:
SourceMap | 含义 |
---|---|
inline-source-map | 报错时将行和列都显示出来 |
cheap-inline-source-map | 报错时只知道哪一行出错了,不知道在哪一列 |
cheap-module-source-map | 生产环境最佳实践,不只管本身的业务代码错误,还要管其余的其余的错误,像loader、其余第三方模块的错误等等 |
eval | eval是打包速度最快的一种方式,但若是遇到业务代码比较复杂的状况下,用eval提示出来的效果可能不太全面 |
module-eval-source-map | 用module,代表不只要显示业务错误,还要显示loader、第三方错误等等 |
cheap-module-eval-source-map | 开发环境最佳实践 |
事实上,若是咱们不采用 WebpackDevServer
的方式来开发的话,那么咱们每一次想要查看编译后的运行结果,都须要先命令行编译 npm run bundle
命令,以后再打开 dist
目录下的 index.html
文件才能从新查看。这样一来二往的,不免效率低下。咱们期待的结果是什么呢?
咱们把 package.json
文件里的 script
进行一番改造,具体代码以下:
"scripts": {
"watch": "webpack --watch",
"bundle": "webpack"
},
复制代码
经过以上代码你们能够看到,将 webpack
后面加上 --watch
字段,而后运行 npm run watch
,就能够每次修改完代码后, webpack
实现自动监听,而不用像以往那样,每修改一次代码都要对再从新运行命令来对 webpack
进行打包。
可是呢,这种方式可能还不够友好,毕竟开发者老是懒惰的,能尽可能让程序来干活就不要用手工来干活。
实际上咱们想要达到的效果是,当咱们运行完 npm run watch
这行命令的时候,不只能自动帮咱们实现打包,同时还能帮咱们打开控制台,而且模拟一些服务器上的特性。那么咱们就能够经过 webpackDevServer
来实现咱们想要的效果。如何使用 webpckDevServer
呢?具体看下方。
咱们如今项目中安装webpackDevServer,具体命令行以下:
npm install webpack-dev-server -D
复制代码
接下来咱们来配置 package.json
文件的 script
。具体代码以下:
"scripts": {
"watch": "webpack --watch",
"start": "webpack-dev-server"
},
复制代码
接下面咱们来配置 webpack.config.js
文件,具体代码以下:
module.exports = {
mode:'development',
devtool: 'source-map',
// 放置入口文件,明确怎么打包
entry:{
main: './src/index.js'
},
devServer: {
contentBase: './dist',
// 当运行完npm run start时,会自动的帮咱们打开浏览器
open: true
},
output: {
//用[]能够生成多个文件
filename: '[name].js',
// 指打包后的文件要放在哪一个文件下
path: path.resolve(__dirname, 'dist')
}
}
复制代码
那么如今,咱们来看下, webpackDevServer
如何作到自动打开浏览器。详情见下图:
你们能够看到,经过 webpackDevServer
,它不但会监听到咱们的文件发生了改变,从新帮咱们进行打包。同时它还会自动的帮咱们从新刷新浏览器,而且会自动地帮咱们打开浏览器。因此用它呢,能够大大提高咱们的代码开发效率。
webpackDevServer
默认咱们服务器的端口号是 8080
,若是咱们想要修改它为其余的端口号,该怎么作呢?
咱们须要在来修改 webpack.config.js
文件下的 DevServer
,具体代码以下:
module.exports = {
mode:'development',
devtool: 'source-map',
// 放置入口文件,明确怎么打包
entry:{
main: './src/index.js'
},
devServer: {
contentBase: './dist',
// 当运行完npm run start时,会自动的帮咱们打开浏览器
open: true,
//修改端口号
port: 3000
},
output: {
//用[]能够生成多个文件
filename: '[name].js',
// 指打包后的文件要放在哪一个文件下
path: path.resolve(__dirname, 'dist')
}
}
复制代码
咱们只须要在 devServer
里面加上一个 port
的配置,便可实现自定义端口号。
同时值得注意的是,当咱们在用 webpackDevServer
帮咱们项目作打包时,它不会自动生成 dist
目录,那这是为何呢?用 webpackDevServer
打包后的项目会放在咱们的电脑内存中,这在某种程度下能够有效的提高项目的打包速度,让打包变得更快。
假设咱们如今要实现一个新增元素的功能,这个功能所要达到的效果是每点击一次按钮,就新添加一次文本 item
。具体实现代码以下:
index.js文件:
import './style.css';
var btn = document.createElement('button');
btn.innerHTML = '新增';
document.body.appendChild(btn);
btn.onclick = function(){
var div = document.createElement('div');
div.innerHTML = 'item';
document.body.appendChild(div);
}
复制代码
style.css文件:
div:nth-of-type(odd){
background: yellow;
}
复制代码
此时浏览器的显示效果以下图所示:
假设咱们如今来给css的背景改个颜色,好比说改为紫色。具体代码以下:
div:nth-of-type(odd){
background: purple;
}
复制代码
此时咱们保存后浏览器会从新进行刷新,以后每个 item
又要从新 append
进来。以下图:
那这种状况下可能就不是咱们想要的结果了。咱们但愿的是,全部的 item
不进行从新刷新,而且当 css
样式改变的时候,对应的 item
颜色也能够获得改变。那么这就要引出 webpackDevServer
中的一个内容:热模块更新 Hot Module Replacement
。接下来咱们来了解热模块更新相关的配置。
热模块更新,即Hot Module Replacement,简称为 HMR
。
接下来咱们在 webpack.config.js
文件夹下进行配置。具体代码以下:
//node的核心模块
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
mode:'development',
devtool: 'source-map',
// 放置入口文件,明确怎么打包
entry:{
main: './src/index.js'
},
devServer: {
contentBase: './dist',
// 当运行完npm run start时,会自动的帮咱们打开浏览器
open: true,
port: 8080,
// 让咱们的webpackDevServer开启hotModuleReplacement这样子的功能
hot: true,
// 即使HMR没有生效,也不让浏览器自动刷新
hotOnly: true
},
module:{
rules:[{
test:/\.(jpg|png|gif)$/,
use:{
loader:'file-loader',
options: {
//placeholder 占位符
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
},{
test:/\.scss$/,
use:[
'style-loader',
{
loader: 'css-loader',
options: {
//代表前面要先走sass-loader和postcss-loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
},{
test:/\.css$/,
use:[
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
plugins: [new HtmlWebpackPlugin({
//代表要引用哪个模板
template: 'src/index.html'
}),new CleanWebpackPlugin(['dist']),
new webpack.HotModuleReplacementPlugin()
],
// 输出,代表webpack应该怎么输出
output: {
// 下载middle:npm install express webpack-dev-middleware -D
publicPath: '/',
//用[]能够生成多个文件
filename: '[name].js',
// 指打包后的文件要放在哪一个文件下
path: path.resolve(__dirname, 'dist')
}
}
复制代码
经过以上代码咱们能够知道,配置 devServer
下的 hot
和 hotOnly
,以及 plugins
下的 new webpack.HotModuleReplacementPlugin()
,来达到热模块更新的效果。
接下来咱们来看一下,进行配置以后,浏览器的效果。详情见下图:
你们能够看到,加上这几个配置以后, item
不会再从新刷新了,而是在原来的基础上进行样式修改。
继续,接下来咱们来了解,如何使用webpack和babel,来编写ES6的语法。
你们都知道,ES6的语法规范是2015年才正式出版的。因此有时候,并非全部的浏览器都支持ES6语法。所以,咱们如今想要作的事情就是,在webpack打包时,可以将ES6的语法转换为ES5的语法。这样,项目运行的时候,浏览器就不会报错了。
那怎么实现这样子的打包呢?接下来咱们一块儿来了解一下。
首先咱们打开babel的官方网站,按照步骤,咱们一步步在 webpack
中使用 babel
。
第一步: 安装 babel-loader
和 @babel/core
这两个库。具体代码以下:
npm install --save-dev babel-loader @babel/core
复制代码
babel-loader
是帮助webpack进行打包使用的一个工具,而 @babel/core
则是 babel
的一个核心库,它可以让 babel
去识别 js
代码里的内容,而后呢把 js
代码转换成 AST
抽象语法树,以后再把抽象语法树编译成一些新的语法。
第二步: 在 webpack.config.js
文件下的配置项里增设规则。具体代码以下:
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
复制代码
第三步: 安装 @babel/preset-env
。具体代码以下:
npm install @babel/preset-env --save-dev
复制代码
为何要安装这个模块呢?实际上,当咱们使用 babel-loader
处理文件时,实际上 babel-loader
只是 webpack
和 babel
之间作通讯的一个桥梁,它只是帮咱们打开了一个通道,可是它并不会帮咱们把 ES6
的语法转换为 ES5
的语法。因此,咱们就还须要借助一些其余的模块,来作这项工做。这个模块就是前面咱们说的,preset-env 。
babel/preset-env
,包含了全部 ES6
转换为 ES5
的语法规则,当使用此模块打包时,就能够把咱们全部 js
中 ES6
的代码转换为 ES5
了。具体配置方式见以上第二步。
经过以上的方式,咱们能够达到将ES6语法转换为ES5语法的效果。可是呢,咱们还要考虑到的一个问题就是,若是遇到像promise这一类新的语法变量,或者时像数组里面map这一类的函数,低版本的浏览器里面,实际上仍是不存在的。虽然咱们作了语法解释和语法翻译,但也只是翻译了一部分。还有一些对象和函数,在低版本的浏览器仍是没有的。
因此呢,这个时候咱们不只要使用 babel/preset-env
作语法转换,还要把这些缺失的变量和函数补充到低版本的浏览器里面。
那怎么补充呢,这个时候咱们就须要借助 babel-polyfill
这个工具来进行补充。接下来说解这个模块的使用操做。
第一步: 定位到官方文档,安装 babel-polyfill
。具体代码以下:
npm install --save @babel/polyfill
复制代码
第二步: 引入该模块。具体代码以下:
import "@babel/polyfill";
复制代码
一般状况下,这段代码放到项目的 js
入口文件下。
第三步: 改造 webpack.cofig.js
文件下的 module
,减小打包大小。具体代码以下:
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [['@babel/preset-env'],{
useBuiltIns: 'usage'
}]
}
}
}
]
}
复制代码
这段代码的意思就是,当用 babel-polyfill
填充低版本浏览器特性的时候,不是把是多有的特性都加进来,而是根据咱们的业务代码来决定到底到加什么。
同时, babel-preset
也有不少其余值得学习的配置属性,这里再也不进行讲解。你们能够自行到官方文档上进行查看~
写完这篇文章的时候,忽然想起上次面试时的面试官。在最后的反问环节问他关于 webpack
的问题,他说 webpack
通常会让对公司业务很熟悉的员工来处理,毕竟前端工程化不是儿戏。
当时我尚未很大的感触,但如今学到这里忽然就想到了那个场景。确实是这样,我这才学了不到它的冰山一角,就已经感到 webpack
的庞大工程了。若是在打包时候,但凡是有一个小地方的配置出现问题,就有可能引起整个项目的不可收拾局面。(固然通常状况下不会出现这样的状况,言重了……)
在学习 webpack
的过程当中,要明确好本身所使用的webpack版本。好比周一刚开始迷迷糊糊的,感受版本4和版本5都差很少。但对于 webpack
来讲,这彻底就是在跟它开玩笑。每个依赖都有4和5对应的版本,而不是说想用哪一个就哪一个。若是胡乱使用的话,无形之中可能会报错到怀疑人生……
所以,肯定好此时用 webpack
打包时所使用的版本,并在使用 npm
依赖时也一样要找到对应的版原本进行使用,下降错误的发生。
到这里,关于webpack的超入门知识就讲到这里啦!但愿对你们有帮助~
本系列文章代码已上传至公众号,后台回复关键词 webpack
便可获取~
- 关注公众号星期一研究室,第一时间关注学习干货,更多精选专栏待你解锁~
- 若是这篇文章对你有用,记得留个脚印jio再走哦~
- 以上就是本文的所有内容!咱们下期见!👋👋👋