面试题总结

Http 与 Https

  1. 请列举常见的HTTP 头及其作用

http 请求是指从客户端到服务器端的请求消息。包括:消息首行中,对资源的请求方法、资源的标 识符及使用的协议.

Accept:告诉服务器,客户端支持的数据类型。

Accept-Charset:告诉服务器,客户端采用的编码。

Accept-Encoding:告诉服务器,客户机支持的数据压缩格式。

Accept-Language:告诉服务器,客户机的语言环境。

Host:客户机通过这个头告诉服务器,想访问的主机名。

If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间。

Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的。(一般用于防盗链)

User-Agent:客户机通过这个头告诉服务器,客户机的软件环境。

Cookie:客户机通过这个头告诉服务器,可以向服务器带数据。

cookie 是临时文件的意思,保存你浏览网页的痕迹,使得再次上同一页面的时候提高网速,判断你 是否登录过这个网站,有些可以帮你自动登录的。

Cookie 就是服务器暂存放在你的电脑里的资料(.txt 格式的文本文件),通过在 HTTP 传输中的状态好 让服务器用来辨认你的计算机。当你在浏览网站的时候,Web 服务器会先送一小小资料放在你的计算 机上,Cookie 会帮你在网站上所打的文字或是一些选择都记录下来。当下次你再访问同一个网站,Web 服务器会先看看有没有它上次留下的 *

Cookie 资料,有的话,就会依据 Cookie 里的内容来判断使用者, 送出特定的网页内容给你。

Connection:客户机通过这个头告诉服务器,请求完后是关闭还是保持链接。

Date:客户机通过这个头告诉服务器,客户机当前请求时间。
  1. 请列举常见的HTTP状态响应码及其意义
1** 信息。服务器收到请求,请继续执行请求
2** 成功。请求被成功接收并处理
3** 重定向。需要进一步操作来完成请求
4** 客户端错误。无法完成请求,或请求包含语法错误
5** 服务器错误。服务器在处理请求的过程中发成错误
  1. 请简述HTTP缓存机制
    HTTP缓存机制

  2. http 与 https 的区别

  • HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
  • 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
  • http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
  • HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

Javascript

  1. 解决跨域的方法,并简述原理
  • 通过jsonp跨域:
    利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。
  • document.domain + iframe跨域
    两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
  • location.hash + iframe
    a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
    具体实现:
A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。
  • window.name + iframe跨域
    通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
  • postMessage跨域
    postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
    a.) 页面和其打开的新窗口的数据传递
    b.) 多窗口之间消息传递
    c.) 页面与嵌套的iframe消息传递
    d.) 上面三个场景的跨域数据传递

用法:postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

  • 跨域资源共享(CORS)
    只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
  • nginx代理跨域
    同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。
  • nodejs中间件代理跨域
    node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。
  • WebSocket协议跨域
    WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
    原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
  1. cookie、session、sessionStorage、localStorage区别
  • cookie:
    存储于浏览器端,单个cookie 保存数据不能超过4k,数据始终在同源的http请求中携带, 有有效期,过期后将会删除
  • session:
    session 存储于服务端,会在一定时间内保存在服务器上。
  • sessionStorage:
    sessionStorage 仅仅是会话级别的存储,它只在当前浏览器关闭前有效,不能持久保持,sessionStorage 的作用域不在不同的浏览器窗口中共享,即使是同一个页面;
  • localStorage:
    localStorage 始终有效,即使窗口或浏览器关闭也一直有效,除非用户手动删除,其才会失效.作用域在所有同源窗口是共享的,与cookie一样
  1. ES6新特性
  • const 和 let
    • let: 声明在代码块内有效的变量。
      特点:
      在存在变理提升(不能在变量声明之前使用)
      let的暂时性死区: 其实与1差不多,只要在块作用域有声明,就不能在本作用域声明前用主个变量。
      不允许重复声明。
    • const: 声明一个只读的常量
      特点:
      一但声明,这个值不能被改变(对于引用类型,是引用的地址不能被改变)
  • 解构赋值: 按照一定模式从数组或对象中提取值,然后对变量进行赋值(先提取,再赋值)
    • 数组
      let [a, b] = [1, 2]
      // 以下的结果为右边数剩下的值所组成的数组
      let [c, d ,...e] = [1, 2, 3, 4]
      // 有默认值的写法
      let [f = 100] = []  // f = 100
      // 其中String也被视为类数组
      let [a, b] = 'abcd' // a = a; b = 
    
    • 对象 :变量名要与对象的属性名一样才可以
      let { foo } = { foo: 1, bar: 2 } // foo = 1
      // 重新命名(后面那个才是新变量)
      let { foo: newFoo } = { foo: 1, bar: 2 } // newFoo = 1
    
  • 模板字符串
const h = 'hello'
`${ h } word`

特点:

  1. ${}中可以使用任意的javaScript表达试、运算、引用对象属性、函数调用等。结果是其返回值。
  2. 可以换行,但是所有的空格和换行会被保留。
  • 函头函数
    特点:
    1. 函数体内的this = 定义时所在的对像
    2. 不可以当作构造函数(不能用new)
    3. 不可以用arguments对像,可以用rest
    4. 不可以用yield命令(不能用作Generator函数)
  • 数组的扩展
    1. 扩展运算符。
    2. 用于替代数组的apply。
    3. call apply bind的区别:
      用于改变this的指向, 第一个参数为this指向的对像,后面的参数是作为函数的参数。
      区加在于:call apply 会即调用,而bind是生成一个等调用的函数。call bind参数是一个个用逗号罗列,而apply 是传入一个数组。
      fn.apply(null, [1, 2, 3])
      fn.call(null, 1, 2, 3)
      fn.bind(null, 1, 2, 3)()
      // 指最大值
      Math.max(...[3,4,5,62,8])
    
    • 合并数组
      // ES5
      [1, 2].concat(3)
      // ES6
      [1, 2, ...[3]]
    
    • 新增的方法:
    1. Array.from()将类数组转为数组
    2. 可遍历的对象(iterable)(Set, Map)
    • 实例的方法
    1. find()findIndex()找出第一个符合条件的成页/下标(位置)
    2. entries()keys()values() 用于遍历数组。(配合for...of)
    3. includes() 是否存在指定无素(返回布尔值)
  • 对象的扩展
      属性的简写:
      let a = 100
      { a }
      // 等同于
      { a: 100 }
    
    方法名同样可以简写,vue中就常常用这种写法:
      export default {
          name: 'VueComp',
          data() {},
          create() {},
      }
      // 等同于
     export default {
        name: 'VueComp',
        data: function() {},
        create: function() {},
      }
    
    属性名可心使用表达式:
      let foo = 'foo'
      let obj = {
          [foo]: 'fooValue'
      }
    
  • 新增一些方法
  1. Object.is()
  2. Object.assign()
  3. 对像的一些遍历:
    Object.keys(), Object.values(), Object.entries()
  for(let key of Object.keys(obj)) {}
  for(let value of Object.values(obj)) {}
  for(let [key,value] of Object.entries(obj)){}

扩展运算符(常用)(es2017新增,在webpack中要另外的babel转换)

  • Symbol
    javascript又新增的一种数据类型(第七种,另外6种为:Undefined、Null、Boolean、String、Number、Object)

    注:symbol作为对象的属性名时不会被for...in,for...of,Object.keys()识别;可以改用Reflect.ownkeys方法.

  • Set、Map

    • Set
      特点:
      1.类似数组,但其成员是唯一的。
      2.是一个构造函数。
      用法:
      数组去重:
        [...new Set([1,1,1,2,3,4,3])]
        Array.from(new Set([1,1,1,2,3,4,3]))
      
    • Map
      特点:为了解决javascript的对象只能用了符串作为键的问题。
      用法: (使用实例的set,get,delete方法增,查,删)
          const m = new Map()
          const obj = {a: 'aa'}
          m.set(obj, 'obj as key')
          m.get(obj) // 'obj as key'
          m.delete(obj)
          也可以在new 时接受一个数组
          const obj = { a: 'aa'}
          const m = new Map([
              ['name': 'ym'],
              [obj, { b: 'bbbb' }]
          ])
      
  • Set、Map、WeakSet 和 WeakMap 的区别
    Set
    1.成员不能重复
    2.只有健值,没有健名,有点类似数组。
    3.可以遍历,方法有add, delete,has
    weakSet
    成员都是对象
    成员都是弱引用,随时可以消失。 可以用来保存DOM节点,不容易造成内存泄漏
    不能遍历,方法有add, delete,has
    Map
    本质上是健值对的集合,类似集合
    可以遍历,方法很多,可以干跟各种数据格式转换
    weakMap
    直接受对象作为健名(null除外),不接受其他类型的值作为健名
    健名所指向的对象,不计入垃圾回收机制
    不能遍历,方法同get,set,has,delete

  • Promise: 是异步编程的一种解决方案。
    特点:状态不受外界影响(有三种状态:padding, fulfilled,redected),一旦状态改变就不会再变。
    用法:

 const p = new Promise((resolve, reject) => {
       setTimeout(() => {
              resolve()
       }, 1000)
 }).then(res => {}).catch(err => {})
 注: then方法有两个参数,第一个是成功的回调,第二个为失败的回调,即:
 .then(res =>{}, err => {})
 但是最好用catch方法, 因为catch方法会捕获then里的错误,then里有错误程序不会中止。

Promise.all():将一组promise再包装成一个promise

var pa = Promise.all([p1, p2, p3])

特点:
1.当所有都fulfilledj时,promise.all才fulfilled

  1. 当只有一个rejected时,promise.all就会rejected
  2. Iterator和for...of
    • Iterator的3个作用:
      1.为各种数据提供统一的,简便的访问接口
      2.使数据结构的成员能按某种次序排列
      3.主要供for...of用

原生有iterator的数据结构:

Array, Map, Set, String, TypeArray, arguments, NodeList , (object是没有的)

  • for...of与其他循环的比较
    1.for循环写法比较麻烦
    2.数组的forEach: 无法用break;return跳出循环。
    3.For...in
    1.数组的键名是数字,而for...in以字符串作为键名
    2.不仅可以遍历键名,还可以遍历手动添加的其他键,包括原型链上的某些情况下,会心任意次序遍历
    3.for...in主要为对象而设计的

  • Generator与async await
    generator是ES6提供的一种异步编程解决方案。使异步写法更像同步。
    Async await是ES2017的标准,是generator的一个语法糖。
    用法:

        async function a() {
                  await ...
                  console.log(111)
                  await ...
        }
        当执行a时,其不会阻塞涵数外面的代码(a内的代码会安顺序执行)
        console.log('开始')
        a()
        console.log('a后面')
        // 开始 -> a后面 -> 111
    
  • setTimeout ,Promise, Async/Await

        async function async1(){
            console.log('async1 start');
            await async2();
            console.log('async1 end')
        }
        async function async2(){
            console.log('async2')
        }
        console.log('script start');
        setTimeout(function(){
            console.log('setTimeout')
        },0);
        async1();
        new Promise(function(resolve){
              console.log('promise1');
              resolve();
        }).then(function(){
            console.log('promise2')
        });
      console.log('script end')
      答案:
      script start
      async1 start
      async2
      promise1
      script end
      promise2
      async1 end
      setTimeout
    

async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。 可以理解为,是让出了线程,跳出了async 函数体

async function 声明将定义一个返回 AsyncFunction 对象的异步函数。
当调用一个 async 函数时,会返回一个 Promise 对象。
当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;
当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。

使用 async 定义的函数,当它被调用时,它返回的其实是一个Promise对象。

await 语法:[return_value] = await expression;
表达式(express):一个 Promise 对象或者任何要等待的值。
返回值(return_value):返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。

当await操作符后面的表达式是一个Promise的时候,它的返回值,实际上就是Promise的回调函数resolve的参数。

我们都知道Promise是一个立即执行函数,但是他的成功(或失败:reject)的回调函数resolve却是一个异步执行的回调。
当执行到resolve()时,这个任务会被放入到回调队列中,等待调用栈有空闲时事件循环再来取走它。

队列任务优先级:promise.Trick()>promise的回调>setTimeout>setImmediate
  1. javascript 判断数据类型的几种方法
    4.1. typeof 直接返回数据类型字段,但是无法判断数组、null、对象,都返回 "object"
    4.2. instanceof 判断某个实例是不是属于原型
// 构造函数
function Fruit(name, color) {
    this.name = name;
    this.color = color;
}
var apple = new Fruit("apple", "red");

// (apple != null)
apple instanceof Object  // true
apple instanceof Array   // false

4.3. 使用** Object.prototype.toString.call()**判断
call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果

Object.prototype.toString.call(1)
"[object Number]"

Object.prototype.toString.call(NaN);
"[object Number]"

Object.prototype.toString.call("1");
"[object String]"

Object.prototype.toString.call(true)
"[object Boolean]"

Object.prototype.toString.call(null)
"[object Null]"

Object.prototype.toString.call(undefined)
"[object Undefined]"

Object.prototype.toString.call(function a() {});
"[object Function]"

Object.prototype.toString.call([]);
"[object Array]"

Object.prototype.toString.call({});
"[object Object]"
  1. 描述DOM事件流

事件流规定包含三个流程:
事件捕获阶段,事件冒泡阶段和处于目标阶段。
首先发生是事件捕获(截获事件),然后是处于目标阶段接收到事件,最后是事件冒泡阶段(对事件作出相应)。
在DOM事件流中,目标元素<div>在事件捕获阶段是不会接受到事件的,下一阶段“处于目标阶段”,事件在<div>上发生,并在事件处理中被看成冒泡阶段的一部分,然后,冒泡阶段发生,事件传播回文档。

  1. js中proto和prototype的区别和关系?

1.对象有属性proto,指向该对象的构造函数的原型对象。
2.方法除了有属性proto,还有属性prototype,prototype指向该方法的原型对象。

VUE

  1. 首页白屏是怎么引起的?怎么解决?

原因:

首页需要加载比较大的js文件, 解决方法是 在路由返回前添加loading
这类问题不仅是vue。因为是spa,而且所有的渲染都在脚本上,js执行需要时间。另外加载js也要时间,所以页面越大,加载时间越长,而且js执行的时间也长,dcl发生的时间点就更晚,所以会白屏.

解决方法:
1.1.预渲染

预渲染就是webpack打包时候渲染,通过无头浏览器
无头浏览器,打包的时候,可以把你index.html的内容放入你这个浏览器,但是你这个浏览器是空白的,然后当你进入页面时候直接加载这个index.html,但是没ajax请求
获取到预渲染的页面html内容,然后再放入index.html,再到CDN,直接请求html(相当于FMP提前到了FP),其实更像另外一种骨架屏,少了ajax请求
但是由于这样做我们只能添加死数据,而不能把ajax请求的数据渲染到首页上,怎么解决呢?
我们可以在app.vue中
<div id="header"></div>
比如要在这个header标签里面加ajax请求
直接在script中请求给它添加数据即可
document.querySelector('#header').html('...')

1.2.同构

何为同构渲染,就是一套代码多端使用
现在有一些框架,Next,Nuxt,类似于渲染就是vue ->json ->vue-server-renderer ->html

1.3.SSR

服务端渲染也可以解决首屏加载慢这个问题,因为服务端会把所有数据全部渲染完成再返回给客户端
ssr =>请求->node->解析 ->吐回给客户端(带请求数据)
但是有一个大问题,重要的是node层,高并发的解决

1.4.路由懒加载

可以通过plugin-syntax-dynamic-import 这个插件

Vue.component('async-component',(resolve)=>{
  import('./AsyncComponent.js')
  .then((AsyncComponent)=>{
    resolve(AsyncComponent.default)
  })
})

但是现在好像直接可以通过箭头函数实现路由懒加载

const app = () =>import('')

1.5.quicklink

quicklink就是在浏览器空闲的时候去指定需要加载的数据,这个是谷歌开源的,可以去看看

1.6.使用Gzip压缩,减少文件体积,加快首屏页面打开速度

前提是服务器那边得开启gzip
前端需要做的事

npm i compression-webpack-plugin -D

vue.config.js

const CompressionPlugin = require("compression-webpack-plugin")

module.exports = {
  configureWebpack: () => {
    if (process.env.NODE_ENV === 'production') {
      return {
        plugins: [
          new CompressionPlugin({
            test: /\.js$|\.html$|\.css$|\.jpg$|\.jpeg$|\.png/, // 需要压缩的文件类型
            threshold: 10240, // 归档需要进行压缩的文件大小最小值,我这个是10K以上的进行压缩
            deleteOriginalAssets: false, // 是否删除原文件
            minRatio: 0.8
          })
        ]
      }
    }
  }
}

1.7.外链CSS,JS文件

很多时候我们在main.js中直接import一些ui库或者css文件啥的,以后可以在index.html,通过script外链引入,这样就不会通过我们的webpack打包

1.8.webpack entry

这个就是将单页改成多页应用,比如一些组件中,vue.js vue-router等插件已经在某个页面使用了,然后给它缓存起来,下次就无需加载

1.9.骨架屏

骨架屏就是在进入项目的FP阶段,给它来一个类似轮廓的东西,当我们的页面加载完成之后就消失,这个也很好做的,很多ui库都有这个东西,可以参考一下

1.10.loading

首页加一个loading或许是最原始的方法了,在index.html里加一个loadingcss效果,当页面加载完成消失

  1. VUE双向数据绑定的原理

Vue的双向数据绑定是基于ES5的Object.defineProperty()的getter和setter,每当数据发生变化,就会执行getter/setter,结合发布者/订阅者的模式,通知订阅者这些变化,进而执行相应的回调函数。

  1. 描述什么是前端路由和基本实现原理

路由的概念来源于服务端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。
在 Web 前端单页应用 SPA(Single Page Application)中,路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)。

hash 实现

1.hash 是 URL 中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL 中的 hash 部分不会引起页面刷新.
2.通过 hashchange 事件监听 URL 的变化,改变 URL 的方式只有这几种:通过浏览器前进后退改变 URL、通过<a>标签改变 URL、通过window.location改变URL,这几种情况改变 URL 都会触发 hashchange 事件

history 实现

1.history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新
2.history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState<a>标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和<a>标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。

  1. Keep-alive的理解

<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。

主要用于保留组件状态或避免重新渲染。
keep-alive 是 Vue 的内置组件,在组件切换过程中将状态保留在内存中,等再次访问的时候,还保持着离开之前的所有状态,而不是重新初始化。也就是所谓的组件缓存。

使用路由vue-router切换组件的时候是不保存状态的,它进行router.push()router.push()router.replace()的时候,旧组件会被销毁,新组件会被新建,然后走一遍完整的生命周期。
所以缓存经常与router-view一起出现:

<keep-alive>
    <router-view /> <!-- 所有路径匹配到的视图组件都会被缓存 -->
</keep-alive>

被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子:activateddeactivated

1.activated:在 keep-alive 组件激活时调用
2.deactivated:在 keep-alive 组件停用时调用

注意: 只有组件被 keep-alive 包裹时,这两个生命周期函数才会被调用。这两个钩子在服务器端渲染期间不被调用。

Webpack配置

1.基本配置

  • entry 入口

指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的.默认值是 ./src/index.js

  • output 输出

告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中

  • loader

webpack 只能理解 JavaScript 和 JSON 文件。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中

  • plugin 插件

loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量

2.图片压缩方案
https://juejin.cn/post/6844903925611495437

3.webpack 中的 file-loader 和 url-loader
** file-loader**

// index.js
import doggy from 'doggy.jpg'

console.log(doggy)
// webpack.config.js
module.exports = {
  // 省略其他配置项
  module: {
    rules: [{
      test: /\.(png|jpg|gif)$/,
      use: {
        loader: 'file-loader'
      }
    }]
  }
}

打包后,file-loader 将 doggy.jpg 移动到了 dist 目录下,并将该图片改名为 11e15173d7f38a223d340822e4364ddb.jpg。

通过配置 name 和 outputPath 选项,可以自定义图片名称和路径。

loader: 'file-loader',
options: {
  name: '[name].[ext]?[hash]',
  outputPath: 'images/'
}

打包后,dist 目录下会生成一个 images 文件夹,里面包含了 doggy.jpg?e43b20c069c4a01867c31e98cbce33c9。

更多 file-loader 的可配置选项及其他内容,参考 file-loader

** url-loader**

url-loader 将图片转化成 base 编码字符串和 main.js 打包在一起。

// webpack.config.js
module.exports = {
  // 省略其他配置项
  module: {
    rules: [{
      test: /\.(png|jpg|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          limit: 8192
        }
      }
    }]
  }
}

上述代码设置了 limit 选项,意思是当图片体积小于 8192 字节时,会转换成 base 编码字符串,当图片体积大于 8192 字节时,默认会使用 file-loader(虽然代码没有配置 file-loader,但还是需要使用 npm i file-loader -D 安装),并且会将配置的选项传递给 file-loader(也就是说上面可以配置 name、outputPath 等选项)。

url-loader 默认 limit 是没有限制,如果没有设置,则不管多大的图片都会转换为 base64 编码字符串。

还可以配置 fallback 选项来指定不满足 limit 条件时应当使用的 loader:

loader: 'url-loader',
options: {
  limit: 8192,
  fallback: 'responsive-loader'
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容