一、在webpack如何配置解析ES6和React?
1、首先安装@babel/core
、@babel/preset-env
、babel-loader
、@babel/preset-react
2、使用babel-loader,babel的配置文件是:.babelrc
{
"presets":[
"@babel/preset-env",//将es6转es5规则
"@babel/preset-react"//解析react jsx
]
}
3、在webpack.config.js中,与entry、output同级的地方写加一个module对象,如下配置
const path = require('path')
module.exports = {
entry:{
index:'./src/index.js',
search:'./src/search.js'
},
output:{
path:path.join(__dirname,'dist'),
filename:'[name].js'//使用占位符
},
module:{
rules:[
{
test:/\.js$/,
use:'babel-loader'//使用babel-loader
}
]
}
}
二、阐述一下webapck热更新以及热更新原理?
1、webapck热更新又称热替换(HotModuleReplacement
),缩写HMR
,在代码文件发生变化之后自动构建,使用新构建的模块代替旧模块,并自动刷新浏览器
2、热更新原理
webpack构建出来的bundle.js本身不具备热更新的能力,HotModulesReplacementPlugin的作用就是将HMR runtime注入到bundle.js,是的bundle.js可以和HMR server建立websocket的通信连接
启动阶段:①②AB
文件系统经过webpack compiler进行编译,将编译好的文件传送给bundle server服务器,然后浏览器以服务的方式启动
修改代码文件:①②③④⑤
本地开发时对文件进行修改后,仍然进过webpack compiler进行编译,将代码发送给HRM server,HMR server() 知道哪些模块或者源代码发生了改变,通过websocket通知HMR Runtime(客户端)哪些模块发生了变化,通常是以jsonp的数据进行传输,HRM Runtime会更新我们的代码
三、文件指纹是什么?如何用?
文件指纹是打包输出的文件名后缀,用作文件的版本管理,常用的有hash
、chunkhash
、contenthash
hash
:与整个项目的构建相关,只要项目文件有修改,整个项目构建的hash值就会改变
chunkhash
:与webpack打包的chunk有关,不同的entry会生成不同的chunkhash值
contenthash
:根据文件内容来定义hash,contenthash值随文件内容的改变而改变
js的文件指纹设置
设置js文件的output的filename,用chunkhash
const path = require('path')
module.exports = {
entry: {
index: './src/index.js',
search:'./src/search.js'
},
output:{
path:path.join(__dirname,'dist'),
filename:'[name]_[chunkhash:8].js'//使用占位符+文件指纹
}
}
css的文件指纹设置
因为css一般是使用style-loader将css样式注入到style标签中,再添加到html的head中,并没有独立的css文件,所以需要使用MiniCssExtractPlugin插件将css文件提取出一个独立文件,利用src的方法添加到head中。
安装mini-css-extract-plugin插件,这个插件不能和style-loader公用
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: {
index: './src/index.js',
search:'./src/search.js'
},
output:{
path:path.join(__dirname,'dist'),
filename:'[name]_[chunkhash].js'//使用占位符
},
mode:'development',
module:{
rules:[
{
test:/.css$/,
use:[
new MiniCssExtractPlugin.loader,"css-loader"
]
},
{
test:/.less$/,
use:[
new MiniCssExtractPlugin.loader,"css-loader","less-loader"
]
}
]
}
}
图片的文件指纹设置
使用file-loader的options中的name,用hash
占位符名称 | 含义 |
---|---|
[ext] | 资源文件后缀 |
[name] | 文件名称 |
[path] | 文件的相对路径 |
[folder] | 文件所在的文件夹 |
[contenthash] | 文件的内容hash,默认是md5生成 |
[hash] | 文件的内容hash,默认是md5生成 |
[emoji] | 一个随机的指代文件内容的emoji |
const path = require('path')
module.exports = {
entry: {
index: './src/index.js',
search:'./src/search.js'
},
output:{
path:path.join(__dirname,'dist'),
filename:'[name]_[chunkhash:8].js'//使用占位符
},
mode:'development',
module:{
rules:[
{
test:/.(png|jpg|gif|txt|svg)$/,
use:[
{
loader:"file-loader",
options:{
name:'img/[name]_[hash:8].[ext]'
}
}
]
}
]
}
}
四、代码压缩
html压缩
修改html-webpack-plugin,设置压缩参数
css压缩
使用optimize-css-assets-webpack-plugin,同时需要安装css预处理器cssnano
js压缩
内置了uglifyis-webpack-plugin,可以自己安装设置参数
五、关于css优化
补齐css3前缀
安装postcss-loader、autoprefixer插件
{
test:/.less$/,
use:[
new MiniCssExtractPlugin.loader,"css-loader","less-loader",
{
loader:'postcss-loader',
options:{
plugins:() => [
require('autoprefixer')({
browsers:['last 2 version','>1%','ios 7']
})
]
}
}
]
}
移动端css px自动转换为rem
安装px2rem-loader -D、lib-flexible -S (-S安装到依赖中)
{
test:/.less$/,
use:[
new MiniCssExtractPlugin.loader,"css-loader","less-loader",
{
loader:'postcss-loader',
options:{
plugins:() => [
require('autoprefixer')({
browsers:['last 2 version','>1%','ios 7']
})
]
}
},
{
loader:'px2rem-loader',
options:{
remUnit:75, // 1rem = 75px,适合750的设计稿
remPrecesion:8 // px转换为rem的后面的小数点位数
}
}
]
}
六、source map是什么?怎么用?
开发环境通过source map定位到源代码,生产环境应该关闭,因为会暴露业务逻辑,或者避免使用inline-、eval-
关键字 | 描述 |
---|---|
eval | 使用eval包裹模块代码 |
source map | 产生.map文件 |
cheap | 不包含列信息 |
inline | 将.map作为DataURL嵌入,不单独生成.map文件 |
module | 包含loader的source map |
七、说一下webpack的构建过程?
初始化参数
从配置文件和shell语句读取和合并参数,得到最终打包参数
开始编译
用得到的参数初始化编译对象,加载所有的配置的插件,执行对象的run方法开始编译
确定入口
根据配置中的entry找出所有的入口文件
编译模块
从入口文件出发,调用所有配置的loader对模块进行翻译,再找出该模块依赖的模块,递归本步骤知道所有入口依赖的文件都经过了处理
完成模块编译
使用loader翻译完所有模块之后,得到了每个模块被翻译后的最终内容和他们之间的依赖关系
输出资源
根据入口和模块之间的依赖关系,组装成一个个包含多个模块的chunk,再把每个chunk转换成一个单独的文件加入到输出列表
输出完成
在确定好输出内容后,根据配置确定输出路径和文件名,把文件内容写到文件系统
简单来说
- 初始化:启动构建命令,获取和合并配置参数,加载plugin,实例化compiler
- 编译:从entry出发,针对每个module串行调用对应的loader去翻译文件,再递归编译该module依赖的module
- 输出:将编译好的module组成成chunk,将chunk转换成文件,将文件输出到文件系统中
八、如何提高webpack构建速度?优化代码打包体积?
代码压缩
见第四点
图片压缩
使用image-webpack-plugin
基础库(基础包)分离
思路:将react、react-dom或者vue包通过cdn引入,不打入bundle中
方法:使用html-webpack-externals-plugin,或者SplitChunkPlugin
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
plugins:[
new HtmlWebpackExternalsPlugin({
externals:[
{
module:'react',
entry:'xxx',//cdn的文件链接
global:'React'
},
{
module:'react-dom',
entry:'xxx',//cdn的文件链接
global:'ReactDom'
}
]
})
]
//与entry在同一级
optimization:{
splitChunks:{
commons:{
test:/(react|react-dom)/,
name:'vendors',
chunks:'all'
}
}
}
公共脚本代码分离
webpack4.0内置的SplitChunksPlugin代替CommonChunkPlugin
//与entry在同一级
optimization:{
splitChunks:{
minSize:0,
cacheGroups:{
commons:{
name:'commons',
chunks:'all',
minChunks:2
}
}
}
}
Tree shaking(摇树优化)-删除无用代码
将没有用的代码删除掉,比如
- 代码不会被执行,不可达到
- 代码执行的结果不会被用到
- 代码只会影响死变量(只读不写)
利用ES6模块的特点:
- 只能作为模块顶层的语句出现
- import的模块只能是字符串常量
- import binding是immutable的
代码擦除:uglify阶段删除无用代码
scope hoisting
构建后的代码会存在大量的闭包,造成体积增大,运行代码时创建的函数作用域变多,内存开销大。scope hoisting将所有的模块代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量防止变量名冲突。
九、说一说loader和plugin的区别
loader在moudle.rules中配置,类型为数组。loader本质上是一个函数,该函数对接收到的内容进行转换,返回转回的结果。因为webapck只认识js,所以loader成了翻译官,对其他类型的资源进行转译的预处理工作。
plugin是plugins中配置,类型为数组,每一个都是plugin的实例。plugin本质上是插件基于事件流框架tapable, 在于解决 loader无法实现的其他事,可以扩展webpack的功能,执行范围更广的任务,从打包优化和压缩一直到重新定义环境中的变量。
十、对 webpack 的了解
webpack 是一个javascript 应用程序的静态模块打包器;将项目作为一个整体,通过一个入口文件,从这个文件开始递归构建一个依赖关系图,包括应用程序中所需要的各个模块,然后将所有这些模块打包成一个或者多个bundle
核心概念
- entry :入口文件,指示 webpack 应该使用哪一个模块,来作为构建项目内部依赖图的开始,可指定一个或多个入口文件
- output : output 属性指示 webpack 在哪里输出它所创建的bundle,以及如何命名这些文件,默认是
./dist
- loader :loader用来处理非 javascript 文件,因为 webpack本身只理解 javascript
- plugins :loader 用来转换某些类型的模块,而插件可以用于执行范围更广的任务,任务包括打包优化压缩代码到重新定义环境中的变量;功能很强大,可以用来执行及其强大的任务
- mode :模式,可选择
development
/production
,可根据模式启用相应模式下的 webpack 内置优化
十一、webpack、grunt和gulp的不同
三者都是前端构建工具
grunt和gulp都是基于任务和流的。找到一个或一类文件,对其做一系列链式操作,更新流上的数据,整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程
webpack是基于入口的。webpack会自动地递归解析入口所需要的加载的所有资源文件,然后用不同的 loader 来处理不同的文件,用plugin来扩展webpack的功能
webpack与前者最大的不同是支持代码分割、模块化、全局分析
十二、常见loader
名称 | 描述 |
---|---|
babel-loader | 使用babel将ES6转换为ES5 |
css-loader | 支持.css文件的加载和解析 |
style-loader | 将css代码加入style标签再注入html文件的头部 |
less-loader | 将.less文件转换为css |
sass-loader | 将.sass文件转换为css |
ts-loader | 将typeScript转换为javascript |
json-loader | 加载json文件 |
file-loader | 将文件输出到一个文件夹中,在代码中通过url去引用 |
url-loader | 与file-loader相似,有一个阈值的区别,小于阈值返回base64,大于阈值交给file-loader处理 |
postcss-loader | 扩展css语法,配置autoprefixer插件自动补齐不同浏览器的css3前缀 |
eslint-loader、tslint-loader | 通过eslint、tslint检查js、ts代码 |
vue-loader | 加载vue.js单文件组件 |
cache-loader | 可以在一些性能开销大的loader之前添加,目的是将结果缓存到磁盘 |
raw-loader | 将文件以字符串的形式引入 |
十三、介绍常见的plugin
名称 | 描述 |
---|---|
CommonsChunkPlugin | 将chunks相同的模块代码提取成公共js |
CleanWebpackPlugin | 在构建之前先清理dist文件夹,清除无用的资源 |
MiniCssExtractPlugin | 将css从bundle文件里提取成一个独立的css文件,替代ExtractTextWebpackPlugin |
CopyWebpackPlugin | 将文件或者文件夹拷贝到构建的输出目录 |
HtmlWebpackPlugin | 自动往index.html中注入打包生成的xxx.bundle.js文件,生成一个全新的html文件 |
UglifysWebpackPlugin | 使用uglify-js压缩 JavaScript |
ZipwebpackPlugin | 将打包的出的资源生成一个zip包 |
DefinePlugin | 允许在编译时(compile time)配置的全局常量 |
HotMoudleReplacementPlugin | 启动热替换模块,主要用于本地启动 |
十四、本地开发是怎么解决跨域的
-
使用webpack-dev-server插件
-
配置webpack.config.js
var WebpackDevServer = require("webpack-dev-server") module.exports = { ... devServer:{ port:'8080', proxy:{ '/api':{ target:'http:127.0.0.1', changeOrigin: true, pathRewrite:{ '^/api':'' } } } } }
十五、是否写过loader和plugin,描述一下编写思路
loader:编写loader时要遵循单一原则,每个loader只做一种转义工作。每个loader拿到的是源文件内容(source),可以通过返回值的方式将处理后的内容输出,也可以调用this.callback()
方法;还可通过this.async()
生成一个 callback 函数,再用这个callback
将处理后的内容输出出去
plugin:相对loader来说比较灵活。webpack 在运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack 提供的api 改变输出结果
十六、怎么配置单页应用和多页应用
单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可
多页应用可使用webpack的AutoWebPlugin来完成简单的自动话构建,前提是项目的目录结构要遵守预设的规范
十七、什么是bundle、chunk、module
bundle:是webpack打包出来的文件
chunk:是webpack在进行模块的依赖分析时分割出来的代码块
module是开发中的单个模块
参考链接
后续会继续更新~~~