精华内容
下载资源
问答
  • webpack面试题

    2021-05-16 14:53:32
    webpack面试题 1. webpack原理 从配置文件定义的模块列表开始,处理应用程序,从入口文件开始递归构建一个依赖图,然后将所有模块打包为少量的bundle,通常只有一个,可由浏览器加载。 2.webpack的优势 (1) ...

    webpack面试题

    1. webpack原理

    从配置文件定义的模块列表开始,处理应用程序,从入口文件开始递归构建一个依赖图,然后将所有模块打包为少量的bundle,通常只有一个,可由浏览器加载。

    2.webpack的优势

    (1) webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
    (2)能被模块化的不仅仅是 JS 了。
    (3) 开发便捷,能替代部分 grunt/gulp的工作,比如打包、压缩混淆、图片转base64等。
    (4)扩展性强,插件机制完善

    3.什么是loader及理解

    (1) loader用于加载某些资源文件。因为webpack本身只能打包common.js规范的js文件,对于其他资源如css,img等,是没有办法加载的,这时就需要对应的loader将资源转化,从而进行加载。

    (2)在webpack.config.js中指定loader。module.rules可以指定多个loader,对项目中的各个loader有个全局概览。

    (3) loader是运行在NodeJS中,可以用options对象进行配置。plugin可以为loader带来更多特性。loader可以进行压缩,打包,语言翻译等等。

    (4)loader从模板路径解析,npm install node_modules。也可以自定义loader,命名XXX-loader。
    (5)语言类的处理器loader:CoffeeScript,TypeScript,ESNext(Bable),Sass,Less,Stylus。任何开发技术栈都可以使用webpack。

    4.常用loaders
    (1)加载scc style-loader、css-loader、less-loader和sass-loader(文件打包解析css less sass),转换成css

    npm install --save-dev style-loader css-loader less-loader sass-loader
    

    (2)加载图片和字体等文件 raw-loader、file-loader 、url-loader

    npm install --save-dev file-loader raw-loader url-loader
    

    (3)加载数据xml和csv csv-loader xml-loader (打包加载解析csv和xml文件数据)

    npm install --save-dev csv-loader xml-loader
    

    (4)校验测试:mocha-loader、jshint-loader、eslint-loader

    npm install --save-dev mocha-loader jshint-loader eslint-loader
    

    (5)编译:babel-loader、coffee-loader、ts-loade

    npm install --save-dev babel-loader coffee-loader ts-loade
    

    5.什么是plugin

    plugin用于扩展webpack的功能。不同于loader,plugin的功能更加丰富,比如压缩打包,优化,不只局限于资源的加载。

    6.常用plugins

    webpack插件,采用不同的plugin完成各类不同的性需求,热更新,css去重之类的问题

    HtmlWebpackPlugin:会在打包结束之后自动创建一个index.html, 并将打包好的JS自动引入到这个文件中。
    clean-webpack-plugin:在打包之前将我们指定的文件夹清空。应用场景每次打包前将目录清空, 然后再存放新打包的内容, 避免新老混淆问题,非官方功能。
    copy-webpack-plugin:打包相关的文档。除了JS/CSS/图片/字体图标等需要打包以外, 可能还有一些相关的文档也需要打包(word等)。文档内容是固定不变的, 我们只需要将对应的文件拷贝到打包目录中即可。
    mini-css-extract-plugin:是一个专门用于将打包的CSS内容提取到单独文件的插件。前面我们通过style-loader打包的CSS都是直接插入到head中的。
    terser-webpack-plugin:压缩js代码
    optimize-css-assets-webpack-plugin:压缩css代码
    image-webpack-loader或img-loader:压缩图片。
    watch:webpack 可以监听打包文件变化,当它们修改后会重新编译打包
    webpack-dev-server
    webpack-dev-server和watch一样可以监听文件变化,两者不要同时配置,防止冲突。
    webpack-dev-server可以将我们打包好的程序运行在一个服务器环境下
    webpack-dev-server可以解决企业开发中"开发阶段"的跨域问题
    可以监听css,js代码且能自动刷新

    7.webpack-dev-middleware 与 webpack-dev-server 关系

    简单理解 webpack-dev-server主要是express + webpack-dev-middleware + webpack-hot-middleware

    8.webpack-dev-server 和 http服务器的区别

    webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,比传统的http服务对开发更加有效。

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

    浏览器在用户访问页面的时候,为了加快加载速度,会对用户访问的静态资源进行存储,但是每一次代码升级或者更新,都需要浏览器去下载新的代码,最方便和最简单的更新方式就是引入新的文件名称。

    在webpack中,可以在output给出输出的文件制定chunkhash,并且分离经常更新的代码和框架代码,通过NameModulesPlugin或者HashedModulesPlugin使再次打包文件名不变。

    10.什么是Tree-sharking?

    tree-sharking 是指在打包中去除那些引入了,但是在代码中没有被用到的那些死代码。

    展开全文
  • Webpack面试题

    2021-05-01 00:34:55
    前言在前端工程化日趋复杂的今天,模块打包工具在我们的开发中起到了越来越重要的作用,其中webpack就是最热门的打包工具之一。说到webpack,可能很多小伙伴会觉得既熟悉又陌生,熟悉是因...

    前言

    在前端工程化日趋复杂的今天,模块打包工具在我们的开发中起到了越来越重要的作用,其中webpack就是最热门的打包工具之一。

    说到webpack,可能很多小伙伴会觉得既熟悉又陌生,熟悉是因为几乎在每一个项目中我们都会用上它,又因为webpack复杂的配置和五花八门的功能感到陌生。尤其当我们使用诸如umi.js之类的应用框架还帮我们把webpack配置再封装一层的时候,webpack的本质似乎离我们更加遥远和深不可测了。

    当面试官问你是否了解webpack的时候,或许你可以说出一串耳熟能详的webpack loaderplugin的名字,甚至还能说出插件和一系列配置做按需加载和打包优化,那你是否了解他的运行机制以及实现原理呢,那我们今天就一起探索webpack的能力边界,尝试了解webpack的一些实现流程和原理,拒做API工程师。

    CgqCHl6pSFmAC5UzAAEwx63IBwE024.png

    你知道webpack的作用是什么吗?

    从官网上的描述我们其实不难理解,webpack的作用其实有以下几点:

    • 模块打包。可以将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。利用打包我们就可以在开发的时候根据我们自己的业务自由划分文件模块,保证项目结构的清晰和可读性。

    • 编译兼容。在前端的“上古时期”,手写一堆浏览器兼容代码一直是令前端工程师头皮发麻的事情,而在今天这个问题被大大的弱化了,通过webpackLoader机制,不仅仅可以帮助我们对代码做polyfill,还可以编译转换诸如.less, .vue, .jsx这类在浏览器无法识别的格式文件,让我们在开发的时候可以使用新特性和新语法做开发,提高开发效率。

    • 能力扩展。通过webpackPlugin机制,我们在实现模块化打包和编译兼容的基础上,可以进一步实现诸如按需加载,代码压缩等一系列功能,帮助我们进一步提高自动化程度,工程效率以及打包输出的质量。

    说一下模块打包运行原理?

    如果面试官问你Webpack是如何把这些模块合并到一起,并且保证其正常工作的,你是否了解呢?

    首先我们应该简单了解一下webpack的整个打包流程:

    • 1、读取webpack的配置参数;

    • 2、启动webpack,创建Compiler对象并开始解析项目;

    • 3、从入口文件(entry)开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树;

    • 4、对不同文件类型的依赖模块文件使用对应的Loader进行编译,最终转为Javascript文件;

    • 5、整个过程中webpack会通过发布订阅模式,向外抛出一些hooks,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。

    其中文件的解析与构建是一个比较复杂的过程,在webpack源码中主要依赖于compilercompilation两个核心对象实现。

    compiler对象是一个全局单例,他负责把控整个webpack打包的构建流程。compilation对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息,每次热更新和重新构建,compiler都会重新生成一个新的compilation对象,负责此次更新的构建过程。

    而每个模块间的依赖关系,则依赖于AST语法树。每个模块文件在通过Loader解析完成之后,会通过acorn库生成模块代码的AST语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。

    最终Webpack打包出来的bundle文件是一个IIFE的执行函数。

    // webpack 5 打包的bundle文件内容
    
    (() => { // webpackBootstrap
        var __webpack_modules__ = ({
            'file-A-path': ((modules) => { // ... })
            'index-file-path': ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { // ... })
        })
        
        // The module cache
        var __webpack_module_cache__ = {};
        
        // The require function
        function __webpack_require__(moduleId) {
            // Check if module is in cache
            var cachedModule = __webpack_module_cache__[moduleId];
            if (cachedModule !== undefined) {
                    return cachedModule.exports;
            }
            // Create a new module (and put it into the cache)
            var module = __webpack_module_cache__[moduleId] = {
                    // no module.id needed
                    // no module.loaded needed
                    exports: {}
            };
    
            // Execute the module function
            __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
    
            // Return the exports of the module
            return module.exports;
        }
        
        // startup
        // Load entry module and return exports
        // This entry module can't be inlined because the eval devtool is used.
        var __webpack_exports__ = __webpack_require__("./src/index.js");
    })
    

    webpack4相比,webpack5打包出来的bundle做了相当的精简。在上面的打包demo中,整个立即执行函数里边只有三个变量和一个函数方法,__webpack_modules__存放了编译后的各个文件模块的JS内容,__webpack_module_cache__用来做模块缓存,__webpack_require__Webpack内部实现的一套依赖引入函数。最后一句则是代码运行的起点,从入口文件开始,启动整个项目。

    其中值得一提的是__webpack_require__模块引入函数,我们在模块化开发的时候,通常会使用ES Module或者CommonJS规范导出/引入依赖模块,webpack打包编译的时候,会统一替换成自己的__webpack_require__来实现模块的引入和导出,从而实现模块缓存机制,以及抹平不同模块规范之间的一些差异性。

    你知道sourceMap是什么吗?

    提到sourceMap,很多小伙伴可能会立刻想到Webpack配置里边的devtool参数,以及对应的evaleval-cheap-source-map等等可选值以及它们的含义。除了知道不同参数之间的区别以及性能上的差异外,我们也可以一起了解一下sourceMap的实现方式。

    sourceMap是一项将编译、打包、压缩后的代码映射回源代码的技术,由于打包压缩后的代码并没有阅读性可言,一旦在开发中报错或者遇到问题,直接在混淆代码中debug问题会带来非常糟糕的体验,sourceMap可以帮助我们快速定位到源代码的位置,提高我们的开发效率。sourceMap其实并不是Webpack特有的功能,而是Webpack支持sourceMap,像JQuery也支持souceMap

    既然是一种源码的映射,那必然就需要有一份映射的文件,来标记混淆代码里对应的源码的位置,通常这份映射文件以.map结尾,里边的数据结构大概长这样:

    {
      "version" : 3,                          // Source Map版本
      "file": "out.js",                       // 输出文件(可选)
      "sourceRoot": "",                       // 源文件根目录(可选)
      "sources": ["foo.js", "bar.js"],        // 源文件列表
      "sourcesContent": [null, null],         // 源内容列表(可选,和源文件列表顺序一致)
      "names": ["src", "maps", "are", "fun"], // mappings使用的符号名称列表
      "mappings": "A,AAAB;;ABCDE;"            // 带有编码映射数据的字符串
    }
    

    其中mappings数据有如下规则:

    • 生成文件中的一行的每个组用“;”分隔;

    • 每一段用“,”分隔;

    • 每个段由1、4或5个可变长度字段组成;

    有了这份映射文件,我们只需要在我们的压缩代码的最末端加上这句注释,即可让sourceMap生效:

    //# sourceURL=/path/to/file.js.map
    

    有了这段注释后,浏览器就会通过sourceURL去获取这份映射文件,通过解释器解析后,实现源码和混淆代码之间的映射。因此sourceMap其实也是一项需要浏览器支持的技术。

    如果我们仔细查看webpack打包出来的bundle文件,就可以发现在默认的development开发模式下,每个_webpack_modules__文件模块的代码最末端,都会加上//# sourceURL=webpack://file-path?,从而实现对sourceMap的支持。

    sourceMap映射表的生成有一套较为复杂的规则,有兴趣的小伙伴可以看看以下文章,帮助理解soucrMap的原理实现:

    Source Map的原理探究

    Source Maps under the hood – VLQ, Base64 and Yoda

    是否写过Loader?简单描述一下编写loader的思路?

    从上面的打包代码我们其实可以知道,Webpack最后打包出来的成果是一份Javascript代码,实际上在Webpack内部默认也只能够处理JS模块代码,在打包过程中,会默认把所有遇到的文件都当作 JavaScript代码进行解析,因此当项目存在非JS类型文件时,我们需要先对其进行必要的转换,才能继续执行打包任务,这也是Loader机制存在的意义。

    Loader的配置使用我们应该已经非常的熟悉:

    // webpack.config.js
    module.exports = {
      // ...other config
      module: {
        rules: [
          {
            test: /^your-regExp$/,
            use: [
              {
                 loader: 'loader-name-A',
              }, 
              {
                 loader: 'loader-name-B',
              }
            ]
          },
        ]
      }
    }
    

    通过配置可以看出,针对每个文件类型,loader是支持以数组的形式配置多个的,因此当Webpack在转换该文件类型的时候,会按顺序链式调用每一个loader,前一个loader返回的内容会作为下一个loader的入参。因此loader的开发需要遵循一些规范,比如返回值必须是标准的JS代码字符串,以保证下一个loader能够正常工作,同时在开发上需要严格遵循“单一职责”,只关心loader的输出以及对应的输出。

    loader函数中的this上下文由webpack提供,可以通过this对象提供的相关属性,获取当前loader需要的各种信息数据,事实上,这个this指向了一个叫loaderContextloader-runner特有对象。有兴趣的小伙伴可以自行阅读源码。

    module.exports = function(source) {
        const content = doSomeThing2JsString(source);
        
        // 如果 loader 配置了 options 对象,那么this.query将指向 options
        const options = this.query;
        
        // 可以用作解析其他模块路径的上下文
        console.log('this.context');
        
        /*
         * this.callback 参数:
         * error:Error | null,当 loader 出错时向外抛出一个 error
         * content:String | Buffer,经过 loader 编译后需要导出的内容
         * sourceMap:为方便调试生成的编译后内容的 source map
         * ast:本次编译生成的 AST 静态语法树,之后执行的 loader 可以直接使用这个 AST,进而省去重复生成 AST 的过程
         */
        this.callback(null, content);
        // or return content;
    }
    

    更详细的开发文档可以直接查看官网的 Loader API。

    是否写过Plugin?简单描述一下编写plugin的思路?

    如果说Loader负责文件转换,那么Plugin便是负责功能扩展。LoaderPlugin作为Webpack的两个重要组成部分,承担着两部分不同的职责。

    上文已经说过,webpack基于发布订阅模式,在运行的生命周期中会广播出许多事件,插件通过监听这些事件,就可以在特定的阶段执行自己的插件任务,从而实现自己想要的功能。

    既然基于发布订阅模式,那么知道Webpack到底提供了哪些事件钩子供插件开发者使用是非常重要的,上文提到过compilercompilationWebpack两个非常核心的对象,其中compiler暴露了和 Webpack整个生命周期相关的钩子(compiler-hooks),而compilation则暴露了与模块和依赖有关的粒度更小的事件钩子(Compilation Hooks)。

    Webpack的事件机制基于webpack自己实现的一套Tapable事件流方案(github)

    // Tapable的简单使用
    const { SyncHook } = require("tapable");
    
    class Car {
        constructor() {
            // 在this.hooks中定义所有的钩子事件
            this.hooks = {
                accelerate: new SyncHook(["newSpeed"]),
                brake: new SyncHook(),
                calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"])
            };
        }
    
        /* ... */
    }
    
    
    const myCar = new Car();
    // 通过调用tap方法即可增加一个消费者,订阅对应的钩子事件了
    myCar.hooks.brake.tap("WarningLampPlugin", () => warningLamp.on());
    

    Plugin的开发和开发Loader一样,需要遵循一些开发上的规范和原则:

    • 插件必须是一个函数或者是一个包含 apply 方法的对象,这样才能访问compiler实例;

    • 传给每个插件的 compilercompilation 对象都是同一个引用,若在一个插件中修改了它们身上的属性,会影响后面的插件;

    • 异步的事件需要在插件处理完任务时调用回调函数通知 Webpack 进入下一个流程,不然会卡住;

    了解了以上这些内容,想要开发一个 Webpack Plugin,其实也并不困难。

    class MyPlugin {
      apply (compiler) {
        // 找到合适的事件钩子,实现自己的插件功能
        compiler.hooks.emit.tap('MyPlugin', compilation => {
            // compilation: 当前打包构建流程的上下文
            console.log(compilation);
            
            // do something...
        })
      }
    }
    

    更详细的开发文档可以直接查看官网的 Plugin API。

    最后

    本文也是结合一些优秀的文章和webpack本身的源码,大概地说了几个相对重要的概念和流程,其中的实现细节和设计思路还需要结合源码去阅读和慢慢理解。

    Webpack作为一款优秀的打包工具,它改变了传统前端的开发模式,是现代化前端开发的基石。这样一个优秀的开源项目有许多优秀的设计思想和理念可以借鉴,我们自然也不应该仅仅停留在API的使用层面,尝试带着问题阅读源码,理解实现的流程和原理,也能让我们学到更多知识,理解得更加深刻,在项目中才能游刃有余的应用。

    相关文档链接

    Webpack官网

    「吐血整理」再来一打Webpack面试题

    如果觉得这篇文章还不错

    点击下面卡片关注我

    来个【分享、点赞、在看】三连支持一下吧

       “分享、点赞在看” 支持一波  

    展开全文
  • webpack 面试题

    2020-11-02 12:06:15
    主要的有 webpack、gulp、rollup webpack 的定位是 模块打包器,gulp 属于构建工具 webpack 优点: (1)可以模块化打包任何资源 (2)适配任何模块系统 (3)适合SPA但页面应用的开发 缺点: (1)配置项太多...

    (一)有哪些前端打包工具?

    主要的有 webpack、gulp、rollup

    webpack 的定位是 模块打包器,gulp 属于 构建工具

    webpack 优点:

    (1)可以模块化打包任何资源

    (2)适配任何模块系统

    (3)适合SPA但页面应用的开发

    缺点:

    (1)配置项太多,学习成本高

    (2)通过 babel 编译后,js 体积过大

     

    (二)Loader 和 Plugin 是做什么的?

    Loader:是加载器,Webpack将一切文件视为模块,但是 webpack 原生只支持打包 js 文件,如果也想解析其他文件,就会用到 loader,Loader 的作用是让 webpack 拥有解析和加载其他类型文件的能力。

    Plugin:是插件,作用是扩展 webpack 的功能,让 webpack 具有更过的灵活性,在 webpack 运行的生命周期中广播出很多事件,Plugin 会监听这些事件,在合适的时机,通过 webpack 提供的 API 改变输出的结果

     

    (三)webpack 编译函数

    const webpack = require('webpack')
    const config = require('./webpack.config.js')
    
    const compiler = webpack(config)
    
    function compilerCallback (err, status) {
      const statusString = status.toString()
      console.log('statusString', statusString)
    }
    
    compiler.run ((err, status) => {
      compilerCallback(err, status)
    })

    webpack 是一个函数,把 config 参数传进去,执行run函数

     

    (三)webpack 构建流程(工作流程)是什么?

    (1)初始化参数:

    从配置文件或者 shell 文件中读取、合并参数,得到最终参数

    shell 参数:就是命令行中传入的参数

    webpack --mode=development

    shell 的优先级高于webpack.config.js 配置文件

    (2)开始编译:

    用得到的最终参数,初始化 Compiler 对象,加载所有的插件(Plugin),并使用 run 方法进行编译,根据配置的参数找出所有的入口文件(entry),Compiler 是编译的核心

    (3)编译模块:

    从入口文件出发,调用所有配置的 Loader 对模块进行编译,再找出该模块依赖的模块,以此循环,直到所有的入口文件都经过编译处理

    (4)完成模块编译:

    在执行完第4步 Loader 翻译完所有模块后,得到了每个模块被编译后的最终内容,以及他们之间的依赖关系

    (5)输出资源:

    根据入口和各个模块之间的依赖关系,组装成一个个包含多个模块的Chunk,再把每一个Chunk 转化成单独的文件,添加至输出列表,这步是可以修改输出内容的最后机会

    (6)输出完成:

    根据配置确定好输出的路径和文件名,把文件内容写入到文件系统

     

    (四)

     

     

    展开全文
  • Webpack 面试题

    2020-09-21 00:12:46
    1. webpack 打包原理 把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载。 2. webpack 的优势 (1) webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目...

    1. webpack 打包原理
    把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载。

    2. webpack 的优势
    (1) webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移;
    (2)能被模块化的不仅仅是 JS 了;
    (3)开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等;
    (4)扩展性强,插件机制完善;

    3. 什么是 loader,什么是 plugin ?
    loader 用于加载某些资源文件。
    因为 webpack 本身只能打包 common.js 规范的 js 文件,对于其他资源如 css,img 等,是没有办法加载的,这时就需要对应的loader 将资源转化,从而进行加载。
    plugin 用于扩展 webpack 的功能。
    不同于 loader,plugin 的功能更加丰富,比如压缩打包,优化,不只局限于资源的加载。

    4. 什么是 bundle,什么是 chunk,什么是 module ?
    bundle: 是由 webpack 打包出来的文件;
    chunk: 是指 webpack 在进行模块依赖分析的时候,代码分割出来的代码块;
    module: 是开发中的单个模块;

    5. webpack 和 gulp 的区别 ?
    webpack:
    webpack 是一个模块打包器,强调的是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源都看成是模块,通过 loader 和 plugin 对资源进行处理。
    gulp:
    gulp是一个前端自动化构建工具,强调的是前端开发的工作流程,可以通过配置一系列的 task,第一 task 处理的事情(如代码压缩,合并,编译以及浏览器实时更新等)。然后定义这些执行顺序,来让 glup 执行这些task,从而构建项目的整个开发流程。自动化构建工具并不能把所有的模块打包到一起,也不能构建不同模块之间的依赖关系。

    6. 什么是模热更新,有什么优点?
    模块热更新是 webpack 的一个功能,它可以使得代码修改之后,不用刷新浏览器就可以更新。在应用过程中替换添加删出模块,无需重新加载整个页面,是高级版的自动刷新浏览器。
    优点:只更新变更内容,以节省宝贵的开发时间。调整样式更加快速,几乎相当于在浏览器中更改样式;

    7. webpack-dev-server 和 http 服务器的区别
    webpack-dev-server 使用内存来存储 webpack 开发环境下的打包文件,并且可以使用模块热更新,比传统的 http 服务对开发更加有效。

    8. 什么是长缓存,在 webpack 中如何做到长缓存优化?
    浏览器在用户访问页面的时候,为了加快加载速度,会对用户访问的静态资源进行存储,但是每一次代码升级或者更新,都需要浏览器去下载新的代码,最方便和最简单的更新方式就是引入新的文件名称。
    优化:在 webpack 中,可以在 output 给出输出的文件制定 chunkhash,并且分离经常更新的代码和框架代码,通过NameModulesPlugin 或者 HashedModulesPlugin 使再次打包文件名不变。

    9. 什么是 Tree-sharking,CSS可以 Tree-shaking 吗?
    Tree-shaking 是指在打包中去除那些引入了,但是在代码中没有被用到的那些死代码。
    在 webpack 中 Tree-shaking 是通过 uglifySPlugin 来 Tree-shakingJS。Css 需要使用 Purify-CSS。

    10. 如何自动生成 webpack 配置?
    webpack-cli /vue-cli /etc … 脚手架工具

    11. webpack 打包优化
    在生产环境中,webpack 执行的时候 build.js 文件太大,每次请求都会消耗很大的流量,如果修改代码,代码不会更新,浏览器记录了缓存,如果同名文件不会发起请求,走缓存;

    使用 readfileSync 读取 package.json 文件中的版本号,把获取的 version(版本号)加入到 output 出口文件 build.js 中,以版本号管理升级的问题,版本一升级所有的资源,都直接重新来,浪费很多不必要的流量,如果文件发生改变那么从新请求 index.html 内的引用也要发生改变;

    以 chunkhash 来解决缓存后修改代码的问题,在每个文件的处理中都可以获取其数字签名,文件内容发生改变,chunkhash 也发生改变,index,html 中的 chunkhash 文件名也发生改名,产生系统升级,不走缓存;

    如果更改 css 或者 js 或者 第三方包,都会触发重新牺牲流量去请求新的 build.js,使用 webpack 的插件 extract-text-webpack-plugin,在插件中通过 contenthash 将 css 分离,css 的更改和 js 的更改互不影响,只要发生改动就能绕过缓存完成升级;

    如果修改 js,会影响所有的 js(里面的内容包括自己写的和第三方包),使用 webpack 插件 CommonsChunkPlugin 分离第三方库,把自己的 js 和第三方包分离,各走各的,第三方包走 vendor;

    改动 main.js 代码会导致重新生成 vendor,使用 manifest 记录到依赖清单,每次只要改动 vorder 或者 main 都会重新生成关联清单,vendor 不会被 main.js 所影响,main.js 也不会被 vendor 所影响;

    假如不走缓存的话,那么 vendor 和 main 的文件还是特别大,使用 webpack 插件 uglifyjs-webpack-plugin 来压缩 js,因为用了ES6,所以使用 yarn 下载,压缩之后 js 文件就小了差不多50%;

    当前效果比之前好了很多,但是还不是最完美的,在没有任何缓存的情况下,用户一进来主页访问消耗的流量还是很大,此时就需要用到按需加载组件,webpack 分块打包,在路由 router 中提供了一个功能,懒加载,不要需要改变任何路由配置,把所有独自默认一开始就加载的组件分块打包(除了全局下的),形成一个个封装的函数,在路由匹配需要渲染的时候才获取组件对象,在页面创建 script 标签请求回来,引入执行…

    12. install
    webpack 是我们需要的模块打包机,webpack-dev-server 用来创建本地服务器,监听你的代码修改,并自动刷新修改后的结果。这些是有关 devServer 的配置

    contentBase,  // 为文件提供本地服务器
    port, // 监听端口,默认8080
    inline, // 设置为true,源文件发生改变自动刷新页面
    historyApiFallback  // 依赖 HTML5 history API,如果设置为 true,所有的页面跳转指向 index.html
    devServer:{
        contentBase: './src' // 本地服务器所加载的页面所在的目录
        historyApiFallback: true, // 不跳转
        inline: true // 实时刷新
    }
     //然后我们在根目录下创建一个'webpack.config.js',在'package.json'添加两个命令用于本地开发和生产发布
    "scripts": {
                "start": "webpack-dev-server",
                "build": "webpack"
            }
    

    13. entry
    entry: 用来写入口文件,它将是整个依赖关系的根

    var baseConfig = {
            entry: './src/index.js'
        }
    

    当我们需要多个入口文件的时候,可以把 entry 写成一个对象

    var baseConfig = {
            entry: {
                main: './src/index.js'
            }
        }
    

    建议使用后面一种方法,因为它的规模会随你的项目增大而变得繁琐

    14. output
    output: 即使入口文件有多个,但是只有一个输出配置

    var path = require('path')
        var baseConfig = {
            entry: {
                main: './src/index.js'
            },
            output: {
                filename: 'main.js',
                path: path.resolve('./build')
            }
        }
    module.exports = baseConfig
    

    如果你定义的入口文件有多个,那么我们需要使用占位符来确保输出文件的唯一性

    output: {
            filename: '[name].js',
            path: path.resolve('./build')
        }
    

    如今这么少的配置,就能够让你运行一个服务器并在本地使用命令npm start或者npm run build来打包我们的代码进行发布

    15. Loader
    loader的作用:
    1、实现对不同格式的文件的处理,比如说将 scss 转换为 css,或者 typescript 转化为 js;
    2、转换这些文件,从而使其能够被添加到依赖图中;
    loader 是 webpack 最重要的部分之一,通过使用不同的 Loader,我们能够调用外部的脚本或者工具,实现对不同格式文件的处理,loader 需要在 webpack.config.js 里边单独用 module 进行配置,配置如下:

    	// test: 匹配所处理文件的扩展名的正则表达式(必须)
        // loader: loader的名称(必须)
        // include/exclude: 手动添加处理的文件,屏蔽不需要处理的文件(可选)
        //  query: 为loaders提供额外的设置选项
        // ex: 
            var baseConfig = {
                // ...
                module: {
                    rules: [
                        {
                            test: /*匹配文件后缀名的正则*/,
                            use: [
                                loader: /*loader名字*/,
                                query: /*额外配置*/
                            ]
                        }
                    ]
                }
            }
    

    要使 loader 工作,需要一个正则表达式来标识我们要修改的文件,然后用一个数组表示
    我们表示我们即将使用的 Loader ,当然我们需要的 loader 需要通过 npm 进行安装。
    例如我们需要解析 less 的文件,那么 webpack.config.js 的配置如下:

    var baseConfig = {
                    entry: {
                        main: './src/index.js'
                    },
                    output: {
                        filename: '[name].js',
                        path: path.resolve('./build')
                    },
                    devServer: {
                        contentBase: './src',
                        historyApiFallBack: true,
                        inline: true
                    },
                    module: {
                        rules: [
                            {
                                test: /\.less$/,
                                use: [
                                    {loader: 'style-loader'},
                                    {loader: 'css-loader'},
                                    {loader: 'less-loader'}
                                ],
                                exclude: /node_modules/
                            }
                        ]
                    }
                }
    
    

    这里介绍几个常用的loader:
    babel-loader: 让下一代的 js 文件转换成现代浏览器能够支持的 JS 文件。babel 有些复杂,所以大多数都会新建一个 .babelrc 进行配置;
    css-loader,style-loader: 两个建议配合使用,用来解析 css 文件,能够解释 @import,url() 如果需要解析 less 就在后面加一个 less-loader;
    file-loader: 生成的文件名就是文件内容的MD5哈希值并会保留所引用资源的原始扩展名;
    url-loader: 功能类似 file-loader,但是文件大小低于指定的限制时,可以返回一个DataURL事实上;
    在使用 less,scss,stylus 这些的时候,npm会提示差什么插件,差什么,安上就行了;

    16. Plugins
    plugins 和 loader 很容易搞混,都是外部引用有什么区别呢?
    事实上他们是两个完全不同的东西。这么说 loaders 负责的是处理源文件的如css、jsx,一次处理一个文件。
    而 plugins 并不是直接操作单个文件,它直接对整个构建过程起作用。
    下面列举了一些我们常用的 plugins 及其用法:
    ExtractTextWebpackPlugin: 它会将入口中引用 css 文件,都打包都独立的 css 文件中,而不是内嵌在 js 打包文件中。
    下面是它的应用:

    var ExtractTextPlugin = require('extract-text-webpack-plugin')
            var lessRules = {
                use: [
                    {loader: 'css-loader'},
                    {loader: 'less-loader'}
                ]
            }
            var baseConfig = {
                // ... 
                module: {
                    rules: [
                        // ...
                        {test: /\.less$/, use: ExtractTextPlugin.extract(lessRules)}
                    ]
                },
                plugins: [
                    new ExtractTextPlugin('main.css')
                ]
            }
    

    HtmlWebpackPlugin:
    作用: 依据一个简单的 index.html 模版,生成一个自动引用你打包后的 js 文件的新 index.html;

    var HTMLWebpackPlugin = require('html-webpack-plugin')
    var baseConfig = {
          // ...
        	plugins: [
                new HTMLWebpackPlugin()
            ]
     }
    

    HotModuleReplacementPlugin: 它允许你在修改组件代码时,自动刷新实时预览修改后的结果;
    注意永远不要在生产环境中使用HMR。这儿说一下一般情况分为开发环境,测试环境,生产环境。
    用法如 new webpack.HotModuleReplacementPlugin()
    webapck.config.js的全部内容:

    const webpack = require("webpack")
            const HtmlWebpackPlugin = require("html-webpack-plugin")
            var ExtractTextPlugin = require('extract-text-webpack-plugin')
            var lessRules = {
                use: [
                    {loader: 'css-loader'},
                    {loader: 'less-loader'}
                ]
            }
            module.exports = {
                entry: {
                        main: './src/index.js'
                    },
                    output: {
                        filename: '[name].js',
                        path: path.resolve('./build')
                    },
                    devServer: {
                        contentBase: '/src',
                        historyApiFallback: true,
                        inline: true,
                        hot: true
                    },
                    module: {
                        rules: [
                            {test: /\.less$/, use: ExtractTextPlugin.extract(lessRules)}
                        ]
                    },
                    plugins: [
                    new ExtractTextPlugin('main.css')
                ]
            }
    

    17. resolve
    配置导入包的路径

     resolve : {
            alias : { //alias别名 修改vue导入的路径
                "vue$" : "vue/dist/vue.js"
            }
        }
    

    18. 产品阶段的构建
    目前为止,在开发阶段的东西我们已经基本完成了。
    但是在产品阶段,还需要对资源进行分别的处理,例如:压缩,优化,缓存,分离 css 和 js。
    首先我们来定义产品环境:

    var ENV = process.env.NODE_ENV
        var baseConfig = {
            // ... 
            plugins: [
                new webpack.DefinePlugin({
                    'process.env.NODE_ENV': JSON.stringify(ENV)
                })
            ]
        }
    

    然后还需要修改我们的 script 命令

    "scripts": {
                "start": "NODE_ENV=development webpack-dev-server",
                "build": "NODE_ENV=production webpack"
            }
    

    process.env.NODE_ENV 将被一个字符串替代,它运行压缩器排除那些不可到达的开发代码分支。
    当你引入那些不会进行生产的代码,下面这个代码将非常有用。

    if (process.env.NODE_ENV === 'development') {
        console.warn('这个警告会在生产阶段消失')
    }
    

    19. 优化插件
    下面介绍几个插件用来优化代码
    OccurenceOrderPlugin: 为组件分配ID,通过这个插件 webpack 可以分析和优先考虑使用最多 的模块,然后为他们分配最小的ID;
    UglifyJsPlugin: 压缩代码;
    下面是他们的使用方法:

    var baseConfig = {
    // ...
    	new webpack.optimize.OccurenceOrderPlugin()
    	new webpack.optimize.UglifyJsPlugin()
    }
    

    然后在我们使用 npm run build 会发现代码是压缩的

    20. 对 webpack 的看法
    (1) webpack 是一个模块打包工具,使用 webpack 管理你的模块依赖,并编译输出她们所需要的静态文件,它能够很好地管理、打包 web开发中所用到的 html、css、js 及各种静态文件,让开发过程更加高效。
    (2) webpack 的两大特色:代码分割和模块处理;

    21. 热重启

    1. 热重启原理:eventsource sse,一旦服务器资源有更新,能够及时通知到客户端,从而实时的反馈到用户界面上。本质上是一个http,通过 response 流实时推送服务器信息到客户端。链接断开后会持续出发重连。_webpack_hmr:每隔10s推送一条在消息到浏览器;
    2. 实现:
      client:创建 new EventSource (“/message”),
      Server:需要返回类型为 text/event-stream 的响应头,发送数据以 data 开头,\n\n 结尾;
      webpack-dev-server 是一个机遇 express 的 web server,监听 8080,server 内部调用 webpack,这样的好处是提供了热加载和热替换的功能;
      webpack-hot-middleware 和 webpack-dev-middleware
    3. EventSource 和 websocket 的区别:
      eventSource 本质仍然是 http,仅提供服务器端到浏览器端的单向文本传输,不需要心跳链接,链接断开回持续重发链接;
      websocket 是基于 TCP 的协议,提供双向数据传输,支持二进制,需要心跳链接,断开链接不会重链;
      EventSource 更简洁轻量,WebSocket 支持行更好(IE10+)。后者功能更强大一点。

    22. 特性
    所有的资源都可以当作一个模块来处理,热替换(不用刷新整个页面),代码拆分和按需加载,拥有灵活的可扩展 plugin 库和loader 模块加载器;

    23. 如何使用常用插件?

    1. HtmlWebpackPlugin 的用法及多入口文件配置:作用是依据一个html模版,生成html文件,并将打包后的资源文件自动引入(title:;template:’‘,fileName:‘’,inject:js插入位置等);
    2. webpack.optimize.commonsChunkPlugin:抽取公共模块,减小打包体积;例如:vue的源码、jquery的源码等:entry:vendor:[‘react’];plugin:new web pack.optimize.CommonsChunkPlugin({name:’vendor’});
    3. loader:
      css:解析 css 代码,在 js 中通过 require 方式引入 css 文件;
      style:通过style的方式引入 {test:/.css$/,loader:’style-loader!css-loader’},二者组合能将css代码写入到js文件中;
    4. 将样式抽取成单独的文件,extract-text-webpack-plugin(filename:‘’);
    5. url-loader:实现图片文字等的打包,有一个 option 选项 limit 属性表示,少于这个限制,则打包成 base64,大于的话,就使用 file-loader 去打包成图片;
    6. postcss:实现浏览器兼容,autoprefixer;
    7. babel:转 es;
    8. hot module replacement:修改代码后,自动刷新实时预览修改后的效果。devServer:{hot:true,inline:true(实时刷新)};
    9. ugliifyJsPlugin:压缩js代码;

    24. 与 gulp 的比较

    1. gulp 是工具链,可以配合各种插件做 js、css 压缩,less 编译等;而 webpack 能把项目中的各种 js、css 文件等打包合并成一个或者多个文件,主要用于模块化方案;
    2. 侧重点不同,gulp 侧重于整个过程的控制管理(像是流水线),通过配置不同的task,构建整个前端开发流程;webpack 则侧重于模块打包;并且 gulp 的打包功能是通过安装 gulp-webpack 来实现的;
    3. webpack 能够按照模块的依赖关系构建文件组织结构;
    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 663
精华内容 265
关键字:

webpack面试题