写在前面
安装node环境
webpack依赖node环境,必须确保已经安装webpack之前,已经安装了node
npm init初始化
手动新建目录比如我这里的testwebpack
在testwebpack目录下执行npm init
。
备注 :在安装webpack之前先使用npm init初始化下项目,这时候项目中就有package.json了,package.json是node的包管理的文件,如果当前项目需要单独用到node相关的包则需要有package.json;这样当别人获取到项目时可以通过npm install下载package.json中的包。
安装webpack
当我们使用的时webpack4+时,则也需要安装webpack-cli,因为webpack的命令放在了webpack-cli中。
// (安装指定版本,不指定默认安装最新)
npm install webpack@4.41.1 --save -dev
npm install webpack-cli --save -dev
// 显示版本号,说明webpack安装成功
webpack -v
注意点
package.json中安装的包,最终都需要把包版本号前面的^
去掉,否则后面包自动更新,导致某些功能跟其他包依赖冲突或者不能用
1. webpack概念
webpack
:是个模块打包工具,把项目中的各种格式文件都作为模块进行统一打包编译
2. webpack之初体验
2.1 webpack两种模式下打包代码
在testwebpack
目录下手动创建src目录,并在src下创建index.js
// testwebpack/src/index.js
console.log('hello webapck');
使用webpack命令打包webpack ./src/index.js -o ./dist/bundle.js
注意上图中黄色的警告,设置mode模式为dev或者prod,没设置默认是prod,prod模式下会对代码进行压缩。
查看打包之后的bundle.js(发现被压缩了,因为不设置默认是prod);可以直接使用Run Code
插件运行这个这个代码
可以先感受下dev模式的bundel.js文件,在testwebpack
目录下手动创建webpack.config.js
配置文件,文件内容如下
// testwebpack/webpack.config.js
module.exports = {
mode: 'development' // 指定开发模式为development
}
命令行执行 webpack ./src/index.js -o ./dist/bundle.js
打包编译,查看bundel.js 如下图(只截图一部分)
2.2 dev模式下打包文件简单解析
在src
下新建a.js
// src/a.js
module.exports = '我是a.js'
// src/index.js
let aa = require('./a.js')
console.log(aa);
console.log('hello webapck');
模式为dev,在命令行执行 webpack ./src/index.js -o ./dist/bundle.js
,打包后的bundel.js如下图:
功能点1:我们从这个解析文件发现webpack的期中一个强大功能是,它以当前文件index.js为入口,查找所有依赖,然后输出;相当于webpack内部实现了require
的功能,并且将依赖关系组织起来
功能点2:webpack以入口文件模块开始将所依赖的其他模块组织起来最终都是输出为配置的出口文件bundle.js,在bundle.js中,是一个自调用的匿名函数,函数的参数是一个对象,对象中的每一项就是一个模块,每一项的key是模块文件名,value是一个函数。
模块加载过程解析
2.3 webpack命令映射
有没有发现我们每次打包都是在命令行执行 webpack ./src/index.js -o ./dist/bundle.js
,这个命令太长了,有没有简洁命令代替?
答案有的,在package.json的script脚本命令中配置下就行
命令映射好处:
如果命令太长是可以采用这种配置;只要在终端运行的命令都是全局的命令;但是script脚本中配置的命令是会优先在本地找(node/moudles),如果没有找到才会使用全局的。
如果不配置script怎么使用局部本地命令?
需要在本地的node/moudles/
下查找可执行的二进制命令,然后手动执行./node_modules/webpack xxxxx
// 未映射之前使用的是:
webpack ./src/main.js -o ./dist/bundle.js
// 映射解析:映射webpack命令到package.json的script脚本中; npm run build == webpack命令;
"scripts": {
"build": "webpack"
},
npm run build ./src/main.js -o ./dist/bundle.js
// 将编译文件和打包输出文件配置到输入输出中,后面直接使用 `npm run build`
npm run build
3. webpack基本配置系列
注意默认webpack的配置文件的名字是webpack.config.js
webpack主要的几个模块配置项:
- 入口配置/出口配置
- loader配置
- plugin插件配置
- mode模式配置(见webpack初体验)
3.1 入口配置
每次不用单独指定入口,可以在webpack.config.js中进行配置
// webpack.config.js
const path = require('path')
module.exports = {
mode: 'development', // 指定为dev模式
entry: './src/index.js', // 指定入口文件
output: {
// 注意这个路径是个必须是绝对路径
path: path.resolve(__dirname, 'dist'), // 在当前目录下添加dist目录,并且将输出的内容放在filename指定的文件中
filename: 'bundle.js'
}
}
在package.json
的script
中添加"build": "webpack"
,这样就可以在命令行终端使用npm run build
打包编译了
// package.json
"scripts": {
"build": "webpack"
},
执行npm run build
结果如下图
备注:这里只是列出了入口文件和出口的简单配置,具体还有多种配置方式,比如字符串方式、对象方式等,具体可查阅官网
3.2 loader配置
webpack默认只能识别处理js文件,那对于图片、css、es6、typescript、vue、JSX等高级语法,这时则需要相应的loader进行转换,转换为可以识别的低级语法
3.2.1 css-loader&style-loader
css-loader
主要作用:是会对@import 和 url()
进行处理,就像js
解析 import/require()
一样
style-loader
主要作用:是将css-loader
解析后的生成的css模块文件以style
的方式引入到打包生成的模板index.html文件的head标签中(默认是插入在head标签的最底部,如果开发人员想自己加样式,那这时候很有可能被打包之后插入到head标签底部的样式覆盖,所以style-loader中提供了改变可插入的位置的选项属性)
less-loader
作用是:把less文件转css文件
// 安装
npm install css-loader --save-dev
npm install style-loader --save-dev
// webpack.config.js中进行配置
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), // 在当前目录下添加dist目录,并且将输出的内容放在filename指定的文件中
filename: 'bundle.[hash:8].js' // bundle.[hash:8].js防止有缓存,所以每次生成不一样的bundle.js就是加hash,后面的 ':8'表示hash的位数
},
module: {
rules: [
{
test: /\.css$/,
use: [ // 将style写成对象写法,把css-loader写成字符串写法说明写法不限制,对象写法好配置
{
loader: 'style-loader',
options: {
insertAt: 'top' // 指定插入haed标签的顶部,因为默认是插入到head标签的底部
}
},
'css-loader']
}
]
},
}
// 代码测试css-loader和style-loader
// a.css
body{
background-color: red;
}
// index.css
@import './a.css';
body {
background-color: pink;
}
// index.js
import './index.css'
let aa = require('./a.js')
console.log(aa);
console.log('hello webpack');
// require('./index.css') 这种方式也可以导入
注意点1:如果没有使用css-loader直接编译打包,webapck报错,无法识别
注意点2:css-loader执行顺序是从右向左,所以use: ['style-loader', 'css-loader', 'less-loader']
注意点3:loader配置有多种写法,字符串、对象
注意点4:如果只配置了css-loader没有配置style-loader,那么最终打包结束生成index.html中不会包含样式文件,换句话说,相当于样式没有引入,因为css-loader只是解析css中的@import和url()路径引入问题
注意点5:注意只有css-loader和style-loader时,dist目录下并没有单独生成打包后css文件,而是以style引入样式的方式直接引入到打包生成的index.html中,如果样式很多时就会很乱并且难以管理容易造成样式覆盖的问题;如果css想跟js打包一样,作为模块打包文件输出,最终以link外链的方式引入到index.html中,那么需要mini-css-extract-plugin
css抽离插件进行配置。(具体见插件部分)
3.2.2 postcss-loader
默认情况下样式属性没有浏览器兼容前缀比如transform
的浏览器兼容前缀-webkit-transform
// 安装: autoprefixer这个包可以给css属性前加浏览器前缀,但是需要postcss-loader进行转换下
npm install postcss-loader autoprefixer --save-dev
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader', // 这里注意postcss-loader的位置是在css-loader解析之前要加浏览器样式兼容前缀
]
}
]
},
}
配置完postcss-loader
后,postcss-loader
怎么知道哪个包可以加前缀呢,所以需要在根目录下创建postcss.config.js
,在这个配置文件中指定下是autoprefixer
这个包
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
};
配置完这些之后,还需要配置针对不同浏览器或者版本的转换规则
在package.json或者单独创建.browserslistrc
进行配置,这里我们再package.json
中进行配置
// package.json
"browserslist": [
"last 2 version",
"> 1%",
"iOS >= 7",
"Android > 4.1",
"Firefox > 20"
]
进行npm run build
打包之后查看main.css
3.2.3 babel-loader
未配置babel-loader之前,如下图:
// 安装
// @babel/core:是babel的核心模块,可以调用transfor转换方法
// @babel/preset-env:是babel预设可以将es6/7转成es5(将插件封装成一个包是预设)
npm install --save-dev babel-loader @babel/core @babel/preset-env
配置'@babel/preset-env'
之后的箭头函数已经转成es5
的function
// webpack.config.js
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env' // @babel/preset-env是babel预设可以将es6/7转成es5(将插件封装成一个包是预设)
]
}
}
}
默认不支持类语法
,如下图报错:
// 根据提示安装支持类属性的插件
npm install --save-dev @babel/plugin-proposal-class-properties
// webpack.config.js
{
test: /\.js$/,
use: {
// options相当于是babel-loader的参数;presets中配置的是预设相当于是一组plugins的打包;plugins是传给babel-loader的插件,也就是babel-loader依赖的插件。
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env' // @babel/preset-env是babel预设可以将es6/7转成es5(将插件封装成一个包是预设)
],
plugins: [
'@babel/plugin-proposal-class-properties'
]
}
},
include: path.resolve(__dirname, 'src'), // 只对当前目录下src中的js生效
exclude: /node_modules/ // 排除node_modules目录
}
配置完@babel/plugin-proposal-class-properties
之后,npm run build
打包输出就不再报错了
@babel/runtime
和 transform后续讨论,暂时还没想明白
babel的两中方式 api和语法
zhuanlan.zhihu.com/p/147083132
blog.windstone.cc/es6/babel/@…
3.2.4 eslint-loader
eslint可以对js的语法进行校验
// 安装eslint进行js语法校验
npm install --save-dev eslint eslint-loader
// webpack.config.js配置
rules: [
{
test: /\.js$/,
use: {
loader: 'eslint-loader',
options: {
enforce: 'pre' // 表示强制eslint-loader要在其他处理js的loader之前执行。正常情况下的loader的enforce都是normal,enforce:post表示在normal的之后执行
}
},
}
}
3.2.5 file-loader
file-loader
:默认会在内部生成一张图片到dist目录,把生成的图片的名字返回回来。
换句话说import w3 from './w3.png'
其实这里返回的w3是被file-loader处理过之后,输出到dist目录下的be7a673b229da4c8f9885f3398dab2d5.png
未使用file-loader
之前,导入图片报错,无法将导入的图片作为一个模块处理
// 安装
npm install file-loader --save-dev
// webpack.config.js
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: 'file-loader'
}
}
配置完file-loader
之后,使用npm run build
进行打包编译,再使用npm run dev
,在浏览器地址栏localhost:8080
,运行结果如下:图片被作为模块打包输出到dist目录文件夹下;并且是时间戳的方式
3.2.6 url-loader
一般都是直接配置url-loader
而不是file-loader
;url-loader
包含了file-loader
的功能,url-loader
可以做限制。比如当图片小多少k时,采用base64编码转化,否则使用file-loader
直接将图片产出。
// 安装
npm install url-loader --save-dev
// webpack.config.js
rules: [
{
test: /\.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
// 图片小于200k时,使用base64编码转化,否则使用file-loader产生真是图片; 1*1024*1024是1M
limit: 200 * 1024
}
}
}
]
当图片大小小于limit限制时,采用base64编码,dist目录下不会输出图片文件
当图片大小大于limit限制时,采用file-loader,会将图片打包输出到dist目录下
3.3 plugin配置
-
plugin:plugin将现有的webpack进行的扩展,而loader只是类型转换,相当于转换器;除了需要安装导入的第三方plugin之外,webpack还内置了一些plugin,可以在webpack.config.js中使用require导入使用
-
使用步骤:1. 先npm安装;2. 再在webpack.config.js中和配置
3.3.1 HtmlWebpackPlugin
介绍:默认情况下都需要开发人员手动创建index.html,然后命令行打包js文件,最终输出打包后的bundle.js文件,然后还需要开发人员手动再把bundle.js文件,以scrpit标签的形式嵌入到index.html中。但是这一切很影响开发效率,有没有自动帮助我们完成这个过程的插件呢?答案就是HtmlWebpackPlugin
(还是需要开发人员在src下创建index.html,HtmlWebpackPlugin自动化的是将src下创建的index.html复制到dist下,并将生成的bundle.js帮开发人员嵌入到dist下的index.html中)
// 安装
npm install html-webpack-plugin --save-dev
配置:
// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'), // 在当前目录下添加dist目录,并且将输出的内容放在filename指定的文件中
filename: 'bundle.[hash:8].js' // bundle.[hash:8].js防止有缓存,所以每次生成不一样的bundle.js就是加hash,后面的 ':8'表示hash的位数
},
// 数组放着所有的webpack插件
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html', // 指定配置模板,最终dist中的模板会根据这里配置的模板生成
filename: 'index.html', // 配置dist中最终生成的模板是名是index.html
minify: { // minify压缩index.html的html代码,因为默认的prod模式的js代码也是被压缩的
removeAttributeQuotes: true, // 去除双引号
collapseWhitespace: true // 全部变成一行显示
},
hash: true, // 给bundle.js加hash戳(备注:通过HtmlWebpackPlugin插件配置的hash选项只会给dist中的index.html中嵌入的bundle.js加hash,但是dist中的bundle.js并没有带hash显示)
})
],
}
注意点1:HtmlWebpackPlugin插件配置的hash和output.filename配置hash的区别
注意点2:只要文件没有修改,那么每次生成的hash码是一样的,只是修改配置文件hash码不变化
3.3.2 mini-css-extract-plugin
dist目录下并没有单独生成打包后css文件,而是以style引入样式的方式直接引入到打包生成的index.html中,如果样式很多时就会很乱并且难以管理容易造成样式覆盖的问题;如果css想跟js打包一样,作为模块打包文件输出,最终以link外链的方式引入到index.html
中,那么需要mini-css-extract-plugin
css抽离插件进行配置。
// 安装
npm install mini-css-extract-plugin --save-dev
// webpack.config.js配置
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.[hash:8].js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
// {
// loader: 'style-loader',
// options: {
// insertAt: 'top'
// }
// },
MiniCssExtractPlugin.loader, // 表示将下面写的css-loader处理后的文件作为单独main.css放在dist输出目录下,并且以link外链的方式导入到index.html中
'css-loader']
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader, // 表示将下面写的css-loader处理后的文件作为单独main.css放在dist输出目录下,并且以link外链的方式导入到index.html中
'css-loader',
'less-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'main.css' // 指定最终打包生成在dist目录下的样式文件名是main.css
})
],
}
备注上面MiniCssExtractPlugin.loader对css和less文件处理完都放在了main.css文件中,如果想分开放,则可以再导入MiniCssExtractPlugin2const MiniCssExtractPlugin2 = require('mini-css-extract-plugin')
3.3.3 CleanWebpackPlugin
CleanWebpackPlugin
可以在每次构建之前,将上一次输出在dist目录下打包文件全部删除,这样防止多次构建dist目录下的打包文件堆积,最终的效果dist目录下只会存放最新生成的打包文件
// 安装
npm install clean-webpack-plugin --save-dev
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin') // 注意这里解构
module.exports = {
mode: 'development',
// 数组放着所有的webpack插件
plugins: [
new CleanWebpackPlugin(),
],
}
3.3.4 optimize-css-assets-webpack-plugin
默认情况下mode: 'production'
模式下的js文件是被压缩,但是css却没有被压缩
optimize-css-assets-webpack-plugin
插件可以压缩优化css;但是一旦开发人员配置了这个插件进行css的压缩优化,那么webpack默认情况下对js的压缩就会失效,所以还需要开发人员安装配置压缩Js的插件uglifyjs-webpack-plugin
// 安装
npm install --save-dev optimize-css-assets-webpack-plugin
npm install --save-dev uglifyjs-webpack-plugin
// webpack.config.js配置
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
optimization: { // 优化项
minimizer: [
new OptimizeCssAssetsWebpackPlugin(), // 压缩css代码
new UglifyjsWebpackPlugin() // 压缩js代码(未配置OptimizeCssAssetsWebpackPlugin之前默认的js压缩调用的就是这个UglifyjsWebpackPlugin进行的js压缩)
]
},
mode: 'production', // development | production
}
注意点:
默认prod
模式下,JS被压缩,css没有被压缩
只配置optimize-css-assets-webpack-plugin
进行css压缩,js的默认压缩会失效
如果手动配置optimize-css-assets-webpack-plugin
进行css压缩,那么要求开发人员必须使用uglifyjs-webpack-plugin
手动配置js压缩
3.3.5 copy-webpack-plugin
一般我们src下的文件都会被打包到dist目录下,那是因为src下的目录有入口文件,从入口文件开始有依赖关系的会被一起打包最终输出到dist目录;但是如果只是单纯的想把某些目录/文件也拷贝到dist目录,比如某个doc文档文件夹,则可以使用copy-webpack-plugin
插件。
// 安装6.2.1版本的,7版本会出现某些问题
npm install copy-webpack-plugin@6.2.1 --save-dev
// webpack.config.js配置
const CopyWebpackPlugin = require('copy-webpack-plugin')
plugins: [
new CopyWebpackPlugin({ // copy指定目录或者文件到dist目录下; ./ 表示dist目录
patterns: [
{ from: 'doc', to: './doc' }
]
}),
],
3.3.6 bannerPlugin
bannerPlugin
可以给打包输出的js和css文件在内容头部加字符串的版权声明。是webpack内置的插件
// webpack.config.js
const Webpack = require('webpack')
plugins: [
new Webpack.BannerPlugin("make by isisxu in 2020~2021") // webpack内置的BannerPlugin插件增加在打包输出的js和css文件头部增加字符串版权声明
],
4. 其他配置
4.1 webpack-dev-server
默认情况下我们打包的js文件,想运行只能在浏览器中以file://xxxindex.html
的文件访问形式,访问index.html网页。但如果我们希望以服务器https://localhost:xxx
域名端口的方式访问,这时候就可以用webapck自带的devServer。
webpack-dev-server还有一个显著的功能,就是我们默认打包出来的dist文件夹的问价都是在磁盘放着,就算通过在浏览器中以file://xxxindex.html
文件访问,还是会很慢;但devserver的功能除了在本地启动一个服务器之外,还会将打包生成的文件放在内存中,而不是磁盘,这样开发人员每次修改文件内容,都会立马被自动编译更新到内存中,因为服务器一直起着。而不像没起服务器时,这次编译就结束了,下次还是需要手动在命令行输入编译命令。
先安装:npm install --save-dev webpack-dev-server
,然后在script中配置命令
"scripts": {
"dev": "webpack-dev-server"
},
接着在webpack.config.js
中配置devServer
module.exports = {
devServer: {
port: 3000, // 指定启动服务器的端口
progress: true, // 打包过程显示进度条
contentBase: './dist', // 指定在 ./dist 目录下启动服务器
inline: true, // 页面实时刷新
open: true // 启动服务器之后自动在浏览器中打开localhost网址,如果不设置则需要手动打开浏览器输入localhost
}
}
直接命令运行npm run dev
就会启动服务器(备注:npm run dev不会生成dist文件夹,因为生成的文件都在内存中,所以不会看到dist目录,访问的直接是内存中的)
4.2 资源多页应用分类
图片输出到dist下的指定目录,配置url-loader
的outputPath
属性;而且响应位置对这个图片的引入也会自动变成image/be7a67....png
css打包到dist下指定目录,配置MiniCssExtractPlugin
的filename
属性:
试想一般都是将图片等静态资源放在cdn上,那如果想给图片,css,js等在输出的时候加上cdn前缀,怎么操作呢?通过配置publicPath
属性
如果只想给图片加cdn的域名前缀,则只需要在url-loader
的图片配置处加publicPath
;不用给output出口配置
***多入口,多出口配置:***如果不使用chunks指定,则默认生成的html会将生成的js文件都引入一边
// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
home: './src/index.js',
other: './src/other.js'
},
output: {
// [name]:方括号中的name表示变量,也就是对'./src/index.js'打包出home.js;再对'./src/other.js'打包输出other.js
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html', // index.html是手动创建的模板
filename: 'home.html', // home.html是依据index.html模板生成的输出到dist目录下,并且home.html中引入的是home.js
chunks: ['home'] // 指定home.html中引入哪个js;如果想home.html中还想引入other.js,则可以配置chunks:['home', 'other']
}),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'other.html',
chunks: ['other']
})
]
}
4.4 source-map
prod
模式下生成的js文件已经压缩打包了,调试困难,无法定位到具体的出错位置;需要借助source-map
如果不处理的话,默认情况提示错误是打包压缩后的文件,错误提示不明显:
点击错误链接跳转后:
4.4.1 source-map
source-map
除了压缩的代码之外,还会在dist目录下单独生成一份源码映射文件
与之对应,并且出错之后,点击能直接定位到出错的行和列
// webpack.config.js
devtool: 'source-map'
注意index.js:23
表示出错在23行,列就是红色波浪线表示的列开始
4.4.2 eval-source-map
eval-source-map
不会在dist目录下产生单独的映射文件,但是可以显示报错的行和列
4.4.2 cheap-module-source-map
cheap-module-source-map
产生一个单独的映射文件,但是不会产生列;
4.4.4 cheap-module-eval-source-map
cheap-module-eval-source-map
不会产生单独的映射文件在dist目录下,会把产生的映射集成在打包后的文件中,不会产生列。
总结:看似配置项很多, 其实只是五个关键字eval
,source-map
,cheap
,module
,inline
的任意组合。这五个关键字每一项都代表一个特性, 这四种特性可以任意组合。它们分别代表以下五种特性(单独看特性说明有点不明所以,别急,往下看):
- eval: 使用eval包裹模块代码
- source-map: 产生
.map
文件 - cheap: 不包含列信息(关于列信息的解释下面会有详细介绍)也不包含loader的sourcemap
- module: 包含loader的sourcemap(比如jsx to js ,babel的sourcemap)
- inline: 将
.map
作为DataURI嵌入,不单独生成.map
文件(这个配置项比较少见)
source-map总结参考
4.5 watch用法
如果想每次打包编译后输出打包编译的文件到dist目录,并且还不需要每次都手动执行npm run build
,可以通过配置watch
开始实时监控,自动打包编译;那么问题来了,watch
实时监控和web-dev-serve
有什么区别呢?区别是web-dev-server
不会将输出静态文件到dist目录下,watch可以
配置了watch之后,当我们执行npm run build
打包编译,不会直接结束退出命令行,而是会停下来实时监控。
// webpack.config.js
module.exports = {
watch: true, // 开启实时监控
watchOptions: {
poll: 1000, // 轮询监控每秒问我 1000次要更新吗
aggregateTimeout: 500, // 防抖 一直输入停下来保存过了500毫秒后开始自动打包编译
ignored: /node_modules/ // 不需要监控的文件目录
}
}
4.6 resolve
Webpack 在启动后会从配置的入口模块出发找出所有依赖的模块,Resolve 配置 Webpack 如何寻找模块所对应的文件。 Webpack内置
JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你也可以根据自己的需要修改默认的规则。
// webpack.config.js配置
resolve:{
alias:{ // alias配置别名,
components: './src/components/',
'react$': '/path/to/react.min.js' //表示以react结尾的导入语句可以被替换
},
}
// 当你通过 import Button from 'components/button' 导入时,实际上被 alias 等价替换成了 import Button from './src/components/button'
有一些第三方模块会针对不同环境提供几分代码。 例如分别提供采用 ES5 和 ES6 的2份代码,这2份代码的位置写在 package.json
文件里,如下:
{
"jsnext:main": "es/index.js",// 采用 ES6 语法的代码入口文件
"main": "lib/index.js" // 采用 ES5 语法的代码入口文件
}
Webpack 会根据 mainFields
的配置去决定优先采用那份代码;Webpack 会按照数组里的顺序去package.json
文件里寻找,只会使用找到的第一个。
假如你想优先采用 ES6 的那份代码,可以这样配置
mainFields: ['browser', 'main'] // mainFields默认值
// webpack.config.js配置
resolve:{
mainFields: ['jsnext:main', 'browser', 'main']
}
导入模块时,没有写后缀,沉默是.js
的后缀,如果想匹配优先匹配其他,比如index.vue
的vue后缀,可以使用extensions
// webpack.config.js
resolve:{
extensions: ['.vue', '.js', '.json']
}
// require('./data'),会优先匹配data.vue,没找到则会接着匹配data.js,没找到接着匹配data.json,还是找不到就报错
5. webpack中的跨域问题
跨域是指一个域下js去请求另一个域。
简单说协议、域名/IP、端口;其中有一个不一样,则认为是跨域。
可以先在本地写个server.js,因为webpack内部已经依赖了express,所以不需要再安装express,express就是node的一个web框架。
直接使用node运行server.js
// src/server.js
let express = require('express')
let app = express()
app.get('/user', (req, res) => {
res.send("我是服务端的返回信息hello")
})
app.listen(3000,'127.0.0.1') // 这里的ip可以省略,默认监听的localhost
执行node server.js后,相当于启动了express提供的web服务器,接着直接在浏览器访问http://localhost:3000/api/user
试想如果在client请求的地址并不是server的服务,这该怎么办呢?借助webpack的devServer做中间代理,将client的请求代理转发到server的服务上。talk is cheap,show you the code
// src/index.js
// 模拟测试client
// 注意这里默认请求的是 http://localhost:8080,但是server.js中启动的是http://localhost:3000,所以跨域了访问不到,
// 提供思路,可以先让client把请求发到webpack的devServe上,devServer是http://localhost:8080服务,然后再让devServer转发到server.js的http://localhost:3000服务上
let xhr = new XMLHttpRequest()
xhr.open('GET', '/api/user', true)
xhr.onload = () => {
console.log(xhr.response);
}
xhr.send()
// src/server.js
let express = require('express')
let app = express()
app.get('/api/user', (req, res) => {
res.send("我是服务端的返回信息hello")
})
app.listen(3000, '127.0.0.1') // 这里的ip可以省略,默认监听的localhost
// webpack.config.js
devServer: {
proxy: {
'/api': 'http://localhost:3000' // 给devServe配置代理,devServer不设置port默认在8080启动,这里表示对http://localhost:8080域名下以/api开头的,会被代理到http://localhost:3000 域名下
}
}
终端node server.js
启动express框架提供的服务器,然后再npm run dev
,运行webpack项目,webpack的配置devServer会被启动。
此时如果直接在地址栏访问http://localhost:8080/api/user
,过程则相当于没走index.js的请求,而是地址栏模拟client,对http://localhost:8080/api/user
地址发起访问,则devServe监听到,直接将其转发到http://localhost:3000/api/user
上,然后返回结果
如果在地址栏直接访问localhost:8080
,过程相当于index.js——>devServer——>server.js
client请求的path能被修改吗?重写path后代理,只需要配置下proxy代理
// webpack.config.js
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '/api': '' } // 表示client请求http://localhost:8080/api/user时,打到devServe的proxy,匹配搭配/api后转发到target指定的域名下,并把原有的path中的/api替换成空,新的代理地址为:http://localhost:3000/user。那么此时服务端的监听服务也是/user了
}
}
}
如果前端想自己mock数据?可以直接在devServer中配置,因为devServer内置了express,并且devServer提供了钩子函数可以写服务券代码。
// src/index.js
let xhr = new XMLHttpRequest()
xhr.open('GET', '/user', true)
xhr.onload = () => {
console.log(11111, xhr.response);
}
xhr.send()
// webpack.config.js
devServer: {
before (app) { // devServer提供的内置钩子函数,before在devServer启动前执行。mock服务端返回json数据
app.get('/user', (req, res) => {
res.json({ data: '我是服务端返回的data' })
})
},
}
执行npm run dev
启动devServe,接着在地址栏访问localhost:8080
问题来了!就问你怕不怕?——> 如果不通过devServer想直接在server里面启动webpack;并且server和webpack共用一个port(这种情况要求服务端和client端必须放在一起)。
完成上面的操作需要借助webpack-dev-middleware
的中间件。走到这里,webpack基本使用掌握的也差不多了,其实webpack就是一个模块
只需要在express启动server之前,将导入的webpack.config.js的编译结果,移交给中间件middleware
,就可以了
// 安装
npm install webpack-dev-middleware --save-dev
// testwebpack/server.js // 注意这里是根目录server.js
let express = require('express')
let webpack = require('webpack') // 导入webpack模块
let middleware = require('webpack-dev-middleware') // 导入中间件模块
let app = express();
let config = require('./webpack.config.js') // 在启动express的server之前,把
let compiler = webpack(config)
app.use(middleware(compiler))
app.get('/user', (req, res) => {
res.send("我是服务端的返回信息hello")
})
app.listen(3000)
cd到根目录命令行执行node server.js
此时访问http://localhost:3000/user
是地址栏模拟client;如果直接http://localhost:3000/
则访问的是,webpack打包的index.html
中打包的index.js
问题系列
问题:为什么配置文件名字叫webpack.config.js
?
问题:如果不想叫webpack.config.js
,能不能更改?
命令行执行打包命令时,添加--config 指定配置文件名
也可以通过script脚本配置,这样直接运行npm run build
时,会先去node/moudels下查找webpack命令,再用webpack命令执行,指定的my.webpack.js
配置文件,再从这个配置文件中读取到入口文件和出口文件,进而进行打包操作
// package.json
"scripts": {
"build": "webpack --config my.webpack.js"
}
问题:为什么需要base64转化图片?
图片的 base64 编码就是可以将一副图片数据编码成一串字符串,使用该字符串代替图像地址。我们所看到的网页上的每一个图片,都是需要消耗一个 http 请求下载而来的(所有才有了 csssprites 技术的应运而生,但是 csssprites 有自身的局限性,下文会提到)。
没错,不管如何,图片的下载始终都要向服务器发出请求,要是图片的下载不用向服务器发出请求,而可以随着 HTML 的下载同时下载到本地那就太好了,而 base64 正好能解决这个问题。
如果图片足够小且因为用处的特殊性无法被制作成雪碧图(CssSprites),在整个网站的复用性很高且基本不会被更新
(具体过程解析可以参考:玩转图片Base64编码 )
问题:为什么require有时候加路径有时候不加?
// 这种不加路径的是模块,在node_modules中查找
require('webpack')
// 加路径的是自己写的文件模块,不在node_modules中
require('./webpack.config.js')
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!