Appearance
webpack
webpack 基本概念
- entry 入口
- 以某个文件为入口开始打包
- 分类
单入口 String
只会输出一个文件
多入口 Array / Object
Array 只会输出一个文件
Object 会输出多个文件 ==> 多页应用(MPA)
- output 输出
- 打包后资源输出到哪里去
- 输出的文件名叫什么
- loader 加载器
- webpack 本身只能识别 json、js 模块,其他模块一旦加载就会报错.需要借助 loader 帮助 webpack 识别其它识别不了的模块
- plugins 插件
- loader 功能有限,要想做功能更加强大的工作交给插件。比如在页面中自动引入打包生成的 js/css, 压缩 css, 拷贝文件等
- mode
- 模式:开发环境(development)和生产环境(production)提供一系列默认配置, 用于简化配置
webpack 基本配置
- 处理 JS 文件
- eslint-loader
在 package.json 中配置 eslintConfig 来指示 eslint-loader 到底要干什么事enfore: 'pre' 优先执行
- babel-loader
在 webpack 配置中配置 babel 来指示 babel-loader 到底要干什么事 babel.config.js: 配置 webpack 的 preset 与 plugin
- 处理 Vue 文件
- vue-loader
- 处理 JSX 文件
- babel-loader
- 处理 CSS 文件
- 开发环境:创建 style 标签插入样式
- style-loader
- css-loader
- postcss-loader
- less-loader / sass-loader / stylus-loader
- 生产环境:提取单独 css 文件,将来通过 link 引入
- MiniCssExtractPlugin.loader(还需要配置插件 new MiniCssExtractPlugin)
- css-loader
- postcss-loader
- less-loader / sass-loader / stylus-loader
- 开发环境:创建 style 标签插入样式
- 处理 HTML 文件
- 目标: 自动引入打包生成的 js/css html-webpack-plugin
- 处理图片/字体/音视频文件
- url-loader / file-loader limit: 10000 小于 10kb 一下的图片会被 base64 处理
webpack配置层面优化
- 优化打包构建速度
- HMR 热模块替换
- 为什么要用?
- 默认情况下,一旦修改了代码,全部代码重新编译刷新,速度慢(全体刷新)
- 有什么作用?
- 只更新修改的模块,其他模块不变(局部更新)
- 怎么使用?
- devServer:
- new webpack.HotModuleReplacementPlugin()
- 注意:
- 默认情况下只有样式文件有 HMR 功能(style-loader),JS 是没有的开启 JS 的 HMR 功能:
- 手写 JS 代码 --> module.hot.accpet('模块路径', () => {})
- 在 Vue 使用 --> vue-loader
- 在 React 使用 --> react-hot-loader
- 为什么要用?
- 缓存
- eslint 和 babel 两个任务处理 JS 文件,时间一般会比较长,为了让其重新构建速度更快, 可以使用缓存。
- eslint --> cache: true
- babel --> cacheDirectory: true
- cache-loader 放置在要缓存 loader 的前面
- 注意:一般只针对耗时长的任务:eslint-loader/babel-loader/vue-loader
- oneOf
- 作用:
- 让模块只被一个 loader 处理,其他的就不看了(原本所有都会判断一下)
- 能够提升打包速度
- 注意:
- eslint-loader: 处理 js, 需要先执行, 将其定义在 oneOf 的外面
- babel-loader: 处理 js, 后执行, 将其定义在 oneOf 的内部
- 作用:
- 多进程打包
- 过去: happyPack 现在: thread-loader
- 用法和 cache-loader 差不多,放在要使用 loader 前面
- 作用:开启多进程处理前面的任务,提升打包速度
- 注意:每个进程开启和通信都有开销,一般只针对耗时长的任务:babel-loader
- HMR 热模块替换
- 兼容性处
- js
- babel-loader: presets: ['@babel/preset-env'] 问题就是只能编译/转换简单语法
- @babel/polyfill: 做复杂语法(新的 APi)兼容,问题是体积太大了
- core-js: 在@babel/preset-env 基础上,增加了 useBuiltIns: 'usage'来实现按需打包
- eslint-loader package.json 中配置 eslintConfig 来指示 eslint-loader 到底要干什么事enfore: 'pre' 优先执行
- css
- postcss-loader
- 内部使用 autoprefixer 插件, 给 w3c 样式自动添加厂商前缀
- package.json 中指定 browserslist 来指示 postcss-loader 兼容性做到什么程度
- 开发环境
- style-loader
- css-loader
- postcss-loader
- less-loader / sass-loader / stylus-loader
- 生产环境
- MiniCssExtractPlugin.loader(还需要配置插件 new MiniCssExtractPlugin)
- css-loader
- postcss-loader
- less-loader / sass-loader / stylus-loader
- vue vue-loader
- html html-webpack-plugin 自动引入打包生成的 js/css
- 图片/字体/音视频文件 url-loader / file-loader limit: 10000 小于 10kb 一下的图片会被 base64 处理
- js
- 拆分打包与压缩
- 作用:
- 抽取公共代码
- 拆分多个文件,减少单个文件体积(避免单次请求时间过长)
- 配置:
- 多入口+ optimization
- 将node_modules抽取成单独模块
- 将多入口的公共模块也抽取成单独模块
- 单入口+optimization+import
- 将node_modules抽取成单独模块
- 动态导入语法import就能将某些文件抽取成单独模块
- import()动态引入模块
- 原生Js:在需要的回调函数中动态加载模块,
import(模块).then()
- Vue:
()=>import('./Foo.vue')
,实现路由组件懒加载
- 多入口+ optimization
- 作用:
- 资源预加载(prefetch)
- 作用
- 让资源提前加载
- 区别:
- preload 让当前页面的要使用资源加载(延后加载)
- prefetch 让后面要使用资源提前加载(当前不需要使用)
- 使用:
- import(/* webpackPrefetch: true */'./xxx')
- import(/* webpackPreload: true */'./xxx') // 没有效果
- 问题:兼容性较差
- 使用chrome团队提供的一个工具包:preload-webpack-plugin
- npm i-D preload-webpack-plugin@next //必须是最新的下一个版本
- 对异步模块包使用:prefetch
- 对同步模块包使用:preload
- 作用
- 生产环境时不生成 SourceMap
- productionSourceMap: false 减少打包文件
- 文件名 hash 化=>利用浏览器缓存
- 对打包文件名用上 contenthash ==> 某个 bundle 对应的模块文件内容发生改变文件名才会变化 ===> 利用浏览器缓存
- hash、chunkhash、contenthash,首先生成效率越来越低,成本越来越高,影响范围越来越小,精度越来越细。
- hash是一整个项目,一次打包,只有一个hash值,是项目级的
- chunhash是从入口entry出发,到它的依赖,以及依赖的依赖,依赖的依赖的依赖,等等,一直下去,所打包构成的代码块(模块的集合)叫做一个chunk,也就是说,入口文件和它的依赖的模块构成的一个代码块,被称为一个chunk。
- contenthash是哈希只跟内容有关系,内容不变,哈希值不变。与chunkhash的区别可以举上面contenthash的例子,同时可以说明contenthash跟内容有关,但是chunkhash会考虑很多因素,比如模块路径、模块名称、模块大小、模块id等等。
- 代码 Tree Shaking
- 效果: 打包时'摇掉'模块中没有被使用的代码 条件: 必须是 ES6 模块化导出且进行代码压缩时
- 必须使用 ES6 模块化(需要禁止@babel/preset-env 转换 ES6 模块化语法 modules: false)
- 开启 webpack 的生产模式(内部启用 TerserPlugin,用来压缩 JS 代码的插件,tree shaking 功能就是这个插件完成的)
- 在 package.json 配置 sideEffects 来指定哪些文件需要进行 tree shaking
说说如何借助webpack来优化前端性能?
> webpack是一个模块打包工具,可以使用webpack管理模块,并分析模块间的依赖关系最终编译输出模块为html、JavaScript和css以及各种静态文件,让开发更加高效
通过webpack优化前端的手段有:
> JS代码压缩、CSS代码压缩、Html文件代码压缩、文件大小压缩、图片压缩、Tree Shaking、代码分离、内联 chunk
nginx
nginx基本功能
* 作为服务器运行前端项目(gshop-client / gshop-admin)
* 作为代理服务器, 转发前端项目的请求到后台接口
* 配置api代理
bash
server {
listen 8081;
server_name localhost;
# 处理所有与后面不匹配的请求
location / {
root D:\work\online\gshop-client; # 项目资源的根目录
index index.html index.htm; # 首页页面
# try_files $uri $uri/ /index.html; # 所有 404 的请求返回 index 页面
}
# 处理所有/api 开头的请求
# 转发到后台接口地址
# 转发时不要去掉/api
location /api {
proxy_pass http://39.98.123.211;
}
}
server {
listen 8082;
server_name localhost;
location / {
root D:\work\online\gshop-admin;
index index.html index.htm;
}
# 所有/api 开头的请求都转发到后台接口地址
# 转发时去掉/prod-api
location /prod-api/ {
proxy_pass http://39.98.123.211/;
}
}
nginx解决404
bash
location / {
# 解决 history 模式, 浏览器刷新 404 问题
try_files $uri $uri/ /index.html; # 所有 404 的请求返回 index 页面
}
token存在sessionstorage还是loaclstorage
token:验证身份的令牌,一般就是用户通过账号密码登录后,服务端把这些凭证通过加君
- 存loaclstorage里,后期每次请求接口都需要把它当作一个字段传给后台
- 存cookie中,会白动发送,缺点就是不能跨域
如果存在localstorage中,容易被xss攻击,但是如果做好了对应的措施,那么是利大于 如果存在cookie中会有CSRF攻击
token的登录流程
- 客户端用账号密码请求登录
- 服务端收到请求后,需要去验证账号密码
- 验证成功之后,服务端会签发一个token,把这 个token发送给客户端
- 容户端收到token后保存起来,可以放在cookie也可以是localstorage
- 客户端每次向服务端发送请求资源的时候,都需要携带这 个token
- 服务端收到请求,接着去验证客户端里的token,验证成功才会返回客户端请求的数据
了解过JWT吗
JSONWebToken 通过了JSON形式作为在web应用中的令牌,可以在各方之间安全的把信息作为JSON对象传输(信息传输、授杈)
JWT的认证流程
- 前端把账号密码发送给后端的接口
- 后端核对账号密码成功后,把用户id等其他信息作为JWT负载,把它和头部分别进base64编码拼接后签名,形成一个JWT (token) .
- 前端每次请求时都会把JWT放在HTTP请求头的Authorization字段内
- 后端检查是否存在,如果存在就验证JVT的有效性(签名是否正确,token是否过期)
- 验证通过后后端使用JWT中包含的用户信总进行其他的操作,井返回对应结果
处理无感登陆
- 在相应其中拦截,判街token返回过期后,调用刷新token的接口
- 后端返回过期时间,前端判断token的过期时间,去调用刷新token的按口
- 写定时器,定时刷新token接口
流程:
- 登录成功后保存token 和 refresh_token
- 在响应拦截器中对401状态码引入刷新token的api方法调用
- 替换保存本地新的token
- 把错误对象里的token替换
- 再次发送未完成的请求
- 如果refresh_token期了,判新是否过期,过期了就清楚所有token重新登录
vue和react对比
- 相同点
- 都有组件化思想
- 都支持服务器端渲染
- 都有Virtual DOM(虚拟dom)
- 数据驱动视图
- 都有支持native的方案:Vue的weex、React的React native
- 都有自己的构建工具:Vue的vue-cli、React的Create React App
- 不同点
- 数据流向的不同。react从诞生开始就推崇单向数据流,而Vue是双向数据流
- 数据变化的实现原理不同。react使用的是不可变数据,而Vue使用的是可变的数据
- 组件化通信的不同。react中我们通过使用回调函数来进行通信的,而Vue中子组件向父组件传递消息有两种方式:事件和回调函数
- diff算法不同。react主要使用diff队列保存需要更新哪些DOM,得到patch树,再统一操作批量更新DOM。Vue 使用双向指针,边对比,边更新DOM