前端工程化面试题

目录

    • 1.什么是 `bundle`, 什么是 `chunk`,什么是`module`?
    • 2.hash chunkhash contenthash三者区别
    • 3.什么是脚手架吗?
    • 4.webpack的核心思想是什么
    • 5. Loader和Plugin的区别
    • 6.有哪些常见的Loader和Plugin,他们各自的作用
    • 7.Webpack 的热更新原理
    • 8.如何优化 Webpack 的构建速度
    • 9.代码分割的本质是什么?有什么意义呢?
    • 10.tree-shaking 的原理
    • 11. linux部署和windows sever服务器区别?
    • 12. 什么是组件?什么是模块化?有什么区别?
    • 13.什么是长缓存,在webpack中如何做到长缓存优化?

1.什么是 bundle, 什么是 chunk,什么是module

module
module是我们经常所说的模块,不管是esModule(import/export或export default)、CommonJs(require/module.exports)、AMD(依赖前置require([‘Ma’,‘Mb’],(a,b)=>_/define({key:value}))都属于module

chunks
chunks是webpack依据module间的引用关系通过代码分割生成的不同chunk文件,同时wenpack也可对chunk文件做些一些操作(如加chunkname)

bundle
bundle是webpack最终经过编译输出output的文件集合,他可以包含多个经过加载和编译后的chunk文件,由于bundle是经过加载和编译的最终源文件,所以直接可以在浏览器运行

2.hash chunkhash contenthash三者区别

webpack实现热更新后,每次更新都会将我们的业务代码和第三方库的代码同时打包更新,降低构建效率,所以需要使用webpack的optimization.splitChunks分离第三方库和业务代码,公共模块直接缓存就不要每次更新都消耗资源

hash 是跟整个项目构建有关,只要项目的文件内容发生变化,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值,所以一旦修改任何一个文件,整个项目的文件缓存都将失效

chunkhash 为避免整个项目的文件因为hash不断变化而导致缓存失效,需要chunkhash,chunkhash根据模块之间引入关系生成不同的chunk文件的同时生成对应的hash值,而不再是所有文件共用同一个hash值 如果需要对chunkhash做进一步优化就需要使用上述所说的optimization.splitChunks或者dllPlugin,可以将公共库以及业务代码抽离而直接缓存公共库,只要公共库只要不发生版本迭代,那么公共库的chunkhash就一直不会变。

contenthash contenthash又是在chunkhash的进一步优化,webpack在根据模块引入关系生成对应的chunk文件,模块可能引入index.css以及index.js,那么当index.js变化而index.css没有变化,则项目更新时inedx.css也会被迫重新加载,导致资源损耗 + 优化方法: 我们可以使用extract-text-webpackplugin(webpack4)里的contenthash值,保证引入css文件所在的模块只要css文件内容不变,就不会重复构建css + 配置方法
var extractTextPlugin = require('extract-text-webpack-plugin') plugins:[ new extractTextPlugin('../css/bundle.[name].[contenthash].css') ]

补充:webpack5已经使用mini-css-extract-plugin代替extractTextPlugin

3.什么是脚手架吗?

脚手架的概念和作用:就是拥有完整的开发环境,帮助我们快速的生成一套既定的项目架构、文件、配置。
使用者只需要专注自己的业务代码即可,不需要使用者单独配置
脚手架的构成:
常见的脚手架的开发环境主要分为三种模式:生产模式,开发模式,测试模式。
以及需要配置完整的路由系统(vue-router,react-router-dom),和状态管理系统(vuex,redux)才能保证开发环境的完整性
常见的脚手架:Vue-cli,Creat-React-app,umi-app

4.webpack的核心思想是什么

万物皆模块:在webpacck的世界中,其他任何资源都可以当做模块的方式引入 代码分割:webapp 的优化关键在于代码体积,当应用体积增大,实现代码的按需加载是刚需,这也是 webpack 出现的根本原因
可定制化:任何一个工具都不可能解决所有问题,提供解决方案才是最可行的,webpack基于可定制化的理念构建,通过插件系统,配置文件,可实现大型项目的定制需求

5. Loader和Plugin的区别

loader是一个转换器

  • 用于对模块源码文件的预编译和转换,,loader描述了webpack如何处理非javascript模块。
  • 没有loader,构建的打包过程无法顺利完成
  • loader作用在打包前
  • 将A文件转换为B文件,操作的是文件,比如将A.scss转换为A.css,是单纯的文件转换过程
    Plugin是插件扩展器
  • plugin构建过程更完整的补充和优化,如使用new UglifyJsPlugin(),new CssMinimizerPlugin()压缩js和css
  • 没有plugin,文件的打包过程可以完成
  • plugin作用于整个打包过程,
  • 针对webpack的打包过程,他不直接操作文件,而是基于事件机制工作,会监听webpack打包过程的事件钩子,执行任务,通过事件钩子拦截webpack的执行

6.有哪些常见的Loader和Plugin,他们各自的作用

常用Loader

  • babel-loader使得webpack可以通过babel转译js代码
  • css-loader转译css文件,会对@import和url()进行处理,就像js解析import/require一样,
  • style-loadder把css-loader转译后的结果插入输出的脚本中显示样式效果
  • sass-loader/less-loader都是用来预编译和转换.sass/.less文件
  • file-loader将一个文件中的加载文件、图片import/require()解析为url,并且将文件发送到输出文件夹,并返回文件的publicURL,
  • url-loader是file-loader功能的扩展和封装,options选项中可以设置对引用图片大小的限制,如果大于等于限制,默认使用file-loader并传递所有参数,如果小于,则默认使用base64编码并返回输出,
// 示例
    use: [
        {
          loader: 'url-loader',//等价写法use:'url-loader'?limit=1024
          options: {
            limit: 8192,
          }
        },
    ]

常用Plugin

  • DllPlugin:作用和optimization.splitChunk的作用相似,都是用某种方法拆分bundles,可以大幅度提升构建速度
  • SplitChunksPlugin:分离公共的第三方模块以及业务代码
  • extract-text-webpackplugin: extract-text-webpackplugin(webpack4)里的contenthash值,保证引入css文件所在的模块只要css文件内容不变,就不会重复构建css
  • MiniCssExtractPlugin:抽离css文件,删除和压缩css代码,本插件是extract-text-webpackplugin插件的webpack5的升级用法,可以实现contenthash
  • HtmlWebpackPlugin:

1、为html文件动态引入外部资源给script、link添加compile(编译)后的hash,防止引用缓文件问题
2、可以生成创建html入口文件,比如单页面可以生成一个html文件入口,多页面生成多个html

  • UglifyjsWebpackPlugin:删除和压缩js文件
  • EslintWebpackPlugin:作用类似eslint-loader(eslint-loader已被弃用),审查代码是否符合编码规范和统一,审查代码是否存在语法错误

7.Webpack 的热更新原理

首先热更新所更新的内容是基于hash值发生改变的文件
更新的原理方法是webpack-dev-server启动本地服务,源码在webpack-dev-server的package.json中的bin命令,可以找到命令的入口文件bin/webpack-dev-server.js
一、webpack启动后,完成webpack所有编译工作,以及监听本地文件变化
二、使用express框架启动本地服务让浏览器可以请求本地的静态资源。
三、本地服务启动后,再启动websocket服务,通过websocket,可以建立本地服务和浏览器的双向通信,这样就可以实现本地文件变化,立马告知浏览器可以更新了

// node_modules/webpack-dev-server/bin/webpack-dev-server.js
// 生成webpack编译主引擎 compiler
let compiler = webpack(config);
// 启动本地服务
let server = new Server(compiler, options, log);
server.listen(options.port, options.host, (err) => {
    if (err) {throw err};
});
// node_modules/webpack-dev-server/lib/Server.js
class Server {
    constructor() {
        this.setupApp();
        this.createServer();
    }

    setupApp() {
        // 依赖了express
        this.app = new express();
    }

    createServer() {
        this.listeningApp = http.createServer(this.app);
    }
    listen(port, hostname, fn) {
        return this.listeningApp.listen(port, hostname, (err) => {
            // 启动express服务后,启动websocket服务
            this.createSocketServer();
        }
    }                                   
}

8.如何优化 Webpack 的构建速度

不要让loader做太多事情,以babel-loader为例
最常见的优化方式是,用include或exclude来帮助我们避免不必要的转译,除此之外,如果我们开启缓存转译结果缓存至文件系统,则至少可以提升两倍工作效率

use:{
  exclude:/(node_module|bower_components)/,
  loader:'babel-loader?cacheDirectory=true'
}

不要放过第三方库,以node_modules为代表,庞大又不可或缺。推荐使用DllPlugin
将loader由单进程转为多进程构建

Happypack–将loader由单进程转为多进程,进程是程序运行的数据集合,是系统资源分配基本单位,一般情况下单核cpu只有一个单进程,多核cpu在node的cpu利用率不足的情况下才会由单进程转为多进程。而Happypack帮我们做了这个事儿。多核并发,最大限度使用多核cpu的作用。大大提升效

可视化工具的使用,找出导致文件体积过大的原因

推荐使用webpack-bundule-analyzer,配置方法和普通的 plugin 无异,它会以矩形树图的形式将包内各个模块的大小和依赖关系呈现出来

9.代码分割的本质是什么?有什么意义呢?

代码分割的本质: 是能够把代码分离到不同的bundle中,避免出现大体积的代码包,然后可以按需加载或并行加载这些文件 + 代码分离的意义: 代码分离可以获取更小的bundle,以及控制资源加载优先级,合理使用可以极大的减少加载时间 + 代码分割的实现方式有三种: 入口起点:使用entry手动分离代码(不建议) 防止重复加载:使用optimization.splitChunks配置选项,可以将第三方公共模块和业务代码直接分离 动态引入:使用import()方法来分离代码,原理是当 Webpack 解析到该语法时,会自动进行代码分割,分割出不同的chunks > 语法:使用的时候再去下载对应的文件,返回一个Promise,当Promise成功后再去执行回调,(动态引入的另一种方式是require.ensure()) import("./math").then(math => { console.log(math.add(16, 26)); });
//所有可能匹配此模式的文件都会自动进行代码拆分。 const loadFile = file => import (` ./ $ { file } ` ) import动态语法实现异步加载的代码演示, js function getComponent(){ return import(./loadash).then(_=>{ const element = document.createElement('div'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; }) } getComponent().then(component=>{ document.body.appendChild(component); })

10.tree-shaking 的原理


作用:tree-shaking可以实现删除项目中未被引用的代码 原理:

//test.js
export const a =1;
export const b = 2;
// main.js
import {a} from './test.js'

对于以上情况,test文件中的变量b如果没有在项目中使用的话,就不会被打包到文件中 使用: 在webpack4中,开启生产环境就会自动开启这个优化功能,也可以手动的引入ModuleConcatenationPlugin的支持

11. linux部署和windows sever服务器区别?

  • 性价比:Linux服务器性价比更高,Linux作为资源管理器和操作系统来说,是开源的,免费的,而正版windows的操作系统是收费的。
  • 性能方面:相同配置的Linux服务器的性能比windows服务器好一些,Linux服务器占用的资源少一点
  • 稳定性方面:Window系统用户量大,因而攻击者多一些,所以暴露了更多的系统安全漏洞。Linux是多用户多进程系统,意味着Linux能够一次性处理大量正在进行的进程,比windows处理的多
  • 安全性方面:Linux系统开源软件的开发方式有助于暴露错误,集众人智慧解决问题,补丁更新更快。这是windows不具备的,Windows的另一个不利因素是其许多应用程序依靠远程过程调用,这就迫使Windows的防火墙没有Linux那样严格。而Linux远程过程调用是限制使用的。

12. 什么是组件?什么是模块化?有什么区别?

组件化
就是基础库或者基础组件,意思是把代码重复的部分提炼出一个个组件供给功能使用

模块化
就是业务框架或者业务模块,也可以理解为框架,意思是把功能进行划分,将同一类型的代码整合在一起,所以模块的功能相对复杂,都属于同一个业务。

区别:
使用:组件的使用能在不同项目(模块)重复应用的代码,而模块按照项目功能需求划分成不同类型的业务框架 目的:组件是复用,解耦,模块是为了隔离、封装 依赖:组件之间低依赖,比较独立,模块之间的依赖可通过路由进行耦合 架构定位:组件位于架构底层,被其它层所依赖,模块位于架构业务层

13.什么是长缓存,在webpack中如何做到长缓存优化?

  • 浏览器在用户访问页面的时候,都会对静态资源进行存储,但是每次代码更新或者升级的时候,我们都需要浏览器去重新加载代码,最方便的方法就是以文件名的方式引入,只下载新的代码块,不加载旧的没有变化的代码块,这就是长缓存,
  • 在webpack4中使用SplitChunkPlugin把第三方库和业务代码分离,由于第三方库的chunkHash未改变,所以只会对改变的业务代码的模块进行更新。而第三方库的代码块因为长缓存而不更新。

你可能感兴趣的:(前端工程化,前端,webpack,javascript)