1、webpack的本质

本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具

现在的前端网页功能丰富,特别是SPA(single page web application 单页应用)技术流行后,JavaScript的复杂度增加和需要一大堆依赖包,还需要解决Scss,Less……新增样式的扩展写法的编译工作。

所以现代化的前端已经完全依赖于webpack的辅助了。

wabpack的基本功能?

  • 代码转换(Loader):TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等等

  • 文件优化(Plugin):压缩 JavaScript、CSS、html 代码,压缩合并图片等

  • 代码分割(代码分离):提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载

  • 模块合并:在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件

  • 自动刷新(HMR热更新):监听本地源代码的变化,自动构建,刷新浏览器

  • 代码校验(ESLint和Stylelint):在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过

  • 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。

代码分割(代码分离)的实现方式?

1. 配置多入口:使用 entry 配置手动地分离代码。
  • 如果入口 chunk 之间包含一些重复的模块,那些重复模块都会被引入到各个 bundle 中。
  • 这种方法不够灵活,并且不能动态地将核心应用程序逻辑中的代码拆分出来。
2. 重复模块打包:2种方式:提取公用依赖配置dependOn  和 SplitChunksPlugin插件
  • 配置 entry 提取公用依赖。配置 dependOn 选项,这样可以在多个 chunk 之间共享模块

 const path = require('path');
 
 module.exports = {
   mode: 'development',
   entry: {
     index: {
       import: './src/index.js',
       dependOn: 'shared',//添加此配置
     },
     another: {
       import: './src/another-module.js',
       dependOn: 'shared',//添加此配置
     },
     shared: 'lodash',//添加此配置
   },
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
   },
+  optimization: {
+    runtimeChunk: 'single',//还需设置 optimization.runtimeChunk: 'single'
+  },
 };
  • SplitChunksPlugin插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。
  const path = require('path');
 
  module.exports = {
    mode: 'development',
    entry: {
      index: './src/index.js',
      another: './src/another-module.js',
    },
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist'),
    },
+   optimization: {
+     splitChunks: { //添加此配置
+       chunks: 'all',
+     },
+   },
  };
3. 动态导入:通过模块的内联函数调用来分离代码。
  • 使用符合 ECMAScript 提案 的 ​ import() 语法来实现动态导入。
  • 使用 webpack 特定的 require.ensure。
4. 预获取/预加载模块(prefetch/preload module)

Webpack v4.6.0+ 增加了对预获取和预加载的支持。

在声明 import 时,使用下面这些内置指令,可以让 webpack 输出 "resource hint(资源提示)",来告知浏览器:

prefetch(预获取):将来某些导航下可能需要的资源
preload(预加载):当前导航下可能需要资源

只要父 chunk 完成加载,webpack 就会添加 prefetch hint(预取提示)。与 prefetch 指令相比,preload 指令有许多不同之处:

  • preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
  • preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
  • preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
  • 浏览器支持程度不同。

gulp/grunt 与 webpack的区别是什么?

三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。

  1. 定位与功能
    • Gulp:是一个基于流的自动化构建工具。它采用了代码优于配置的策略,使得学习和使用变得更为简单。Gulp通过流(stream)的概念来简化多任务之间的配置和输出,从而提高了任务执行的效率。
    • Grunt:是一套前端自动化工具,主要用于处理反复重复的任务,如编译、压缩、合并文件和简单的语法检查等。Grunt通过Gruntfile.js文件进行配置,使得任务管理更为灵活。
    • Webpack:是一个模块化管理工具和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。通过loader的转换,任何形式的资源都可以视作模块,如CommonJs模块、AMD模块、ES6模块、CSS、图片等。
  2. 处理方式
    • Gulp和Grunt在处理任务时,通常是将文件从磁盘读取到内存中,完成操作后再写回磁盘。而Webpack在处理资源时,更注重模块之间的依赖关系,通过构建依赖图来优化打包结果。
  3. 使用场景
    • Gulp和Grunt更多地用于任务处理,如文件的编译、压缩和合并等。
    • Webpack则更适用于大型复杂的前端站点构建,它能够处理各种类型的资源,并通过模块化的方式优化资源加载和性能。
  4. 配置方式
    • Gulp和Grunt的配置相对独立,每个任务都需要单独配置。而Webpack则通过loader和plugin来扩展功能,使得配置更为灵活和强大。

webpack和vite的区别?重点!!!

  1. 原理
    • Webpack是一个模块打包器,它会分析项目的结构,找出JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。
    • Vite则采用了基于ES Module,利用浏览器的原生模块特性导入代码,利用浏览器去解析import,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。
  2. 速度
    • Webpack在打包时会将整个项目进行全量构建,即使使用热模块替换(HMR)也需要一定时间。
    • Vite则采用按需编译的方式,只对改动的模块进行编译,从而极大地提高了编译速度。
  3. 插件兼容性
    • Webpack拥有丰富的插件生态,基本上大部分的前端工程化需求都可以通过插件实现。
    • Vite虽然兼容Rollup插件,但其自身的插件生态相对较弱,可能在一些特殊需求上无法满足。
  4. 开发模式
    • Webpack使用传统的开发模式,在开发阶段需要将所有的代码打包成一个或多个bundle,然后在浏览器中进行动态加载
    • Vite则采用ES模块原生的开发模式,在开发阶段不需要将所有代码打包成一个bundle,而是以原生ES模块的方式直接在浏览器中加载和运行文件
  5. 配置复杂度
    • Webpack的配置相对复杂,对新手不够友好。
    • Vite在设计上更注重开箱即用,大部分场景下用户无需自己写配置文件。
  6. 热更新机制
    • Webpack的热更新需要整个模块链重新打包和替换,对于大型项目可能会有延迟。
    • Vite的热更新则只会针对改动的模块进行更新,提高了更新速度。

2、webpack的打包原理

Webpack的打包原理主要是基于模块化的思想,将项目中的各个文件(包括JavaScript、CSS、图片等静态资源)视为模块,并根据这些模块之间的依赖关系进行静态分析。然后,Webpack会根据指定的规则将这些模块打包成一个或多个静态资源文件(bundle),以供浏览器加载和执行。

3、webpack3和webpack4的区别

  1. webpack4引入了持久化缓存,使得重新构建的速度大大加快。
  2. 新增了mode参数来表示是开发还是生产(development/production),production 侧重于打包后的文件大小,development侧重于goujiansud移除loaders。
  3. 必须使用rules(在3版本的时候loaders和rules 是共存的但是到4的时候只允许使用rules)移除了CommonsChunkPlugin (提取公共代码),用optimization.splitChunks和optimization.runtimeChunk来代替支持es6的方式导入JSON文件,并且可以过滤无用的代码。

4、webpack的核心概念

1. Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。告诉webpack要使用哪个模块作为构建项目的起点,默认为./src/index.js

//单个入口写法
module.exports = {
  entry: {
    main: './path/to/my/entry/file.js',
  },
};
//多个入口写法,分离 app(应用程序) 和 vendor(第三方库) 入口
module.exports = {
  entry: {
    main: './src/app.js',
    vendor: './src/vendor.js',
  },
};
//在 webpack < 4 的版本中,通常将 vendor 作为一个单独的入口起点添加到 entry 选项中,以将其编译为一个单独的文件(与 CommonsChunkPlugin 结合使用)。而在 webpack 4 中不鼓励这样做。而是使用 optimization.splitChunks 选项,将 vendor 和 app(应用程序) 模块分开,并为其创建一个单独的文件。不要为 vendor 或其他不是执行起点创建 entry。

2. output :出口,告诉webpack在哪里输出它打包好的代码以及如何命名,默认为./dist

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js',
  },
};

3. mode:模式,通过选择 developmentproduction 或 none 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production

string = 'production': 'none' | 'development' | 'production'
module.exports = {
  mode: 'production',
};

4. Loader:模块转换器,用于把模块原内容按照需求转换成新内容。

//loader在哪配置
module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.ts$/, use: 'ts-loader' },
    ],
  },
};

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

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件

module.exports = {
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};

6. 浏览器兼容性:Webpack 支持所有符合 ES5 标准 的浏览器(不支持 IE8 及以下版本)。webpack 的 import() 和 require.ensure() 需要 Promise。如果你想要支持旧版本浏览器,在使用这些表达式之前,还需要 提前加载 polyfill

7. 环境(environment):Webpack 5 运行于 Node.js v10.13.0+ 的版本。

8. Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。

9. Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。

5、你是如何提高webpack构件速度的?

多入口情况下,使用CommonsChunkPlugin来提取公共代码

通过externals配置来提取常用库

module.exports = {
//告诉webpack哪些模块不需要被打包进bundle中,以某种方式(如CDN)在全局环境中可用。
  externals: {
    'vue': 'Vue',
    'vue-router': 'VueRouter',
    'vuex': 'Vuex',
    'axios': 'axios',
    "CKEDITOR": "window.CKEDITOR"
  },
}

利用DllPlugin和DllReferencePlugin预编译资源模块通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。

//DllPlugin的配置通常涉及在webpack配置文件中引入DllPlugin,并对其进行相应的设置。以下是一个基本的DllPlugin配置示例:
const DllPlugin = require('webpack/lib/DllPlugin');

module.exports = {  
  // ... 其他webpack配置 ...  
  plugins: [  
    new DllPlugin({  
      name: '[name]', // 用于指定全局变量名,供其他模块访问该DLL  
      path: '[path].json' // 用于指定JSON文件的输出路径,该JSON文件包含了该DLL的信息  
    })  
  ]  
};

//DllReferencePlugin的配置通常涉及到指定context和manifest。manifest是一个JSON文件,它包含了在DllPlugin构建过程中生成的依赖信息。以下是一个基本的DllReferencePlugin配置示例:

const webpack = require('webpack');  
  
module.exports = {  
  // ... 其他的webpack配置 ...  
  plugins: [  
    new webpack.DllReferencePlugin({  
      context: __dirname, // 这里的值应与DllPlugin中的context保持一致  
      manifest: require('./path/to/manifest.json') // 指向DllPlugin生成的manifest文件  
    })  
  ]  
};

使用Happypack 实现多线程加速编译

使用webpack-uglify-paralle来提升uglifyPlugin的压缩速度。

原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度。

使用Tree-shaking和Scope Hoisting来剔除多余代码。

//使用 ES2015 模块语法:确保你的代码使用 import 和 export 语法,而不是 CommonJS 的 require 和 module.exports。
//在 package.json 中设置 "sideEffects": false:这告诉 Webpack 忽略那些没有副作用的文件(如 CSS 文件)。如果你的项目中有副作用(比如某些文件仅用于设置全局变量),则需要显式列出这些文件。
//在 Webpack 配置中启用优化:确保你开启了 optimization.usedExports 和 optimization.minimize。

// package.json  
{  
  "name": "your-project",  
  "sideEffects": false,  
  // ... 其他字段  
}

// webpack.config.js  
module.exports = {  
  // ... 其他配置  
  optimization: {  
    minimize: true,  
    usedExports: true, // 开启 Tree Shaking  
    sideEffects: true, // 允许 Webpack 根据 package.json 的 sideEffects 字段来剔除未使用的模块  
  },  
  module: {  
    rules: [  
      // ... 其他 loader 配置  
    ],  
  },  
};


//Scope Hoisting 是一种减少函数声明数量并优化输出束大小的优化技术。默认情况下,Webpack 会为每个模块创建一个新的作用域,这可能会导致输出文件包含大量的函数声明。Scope Hoisting 通过将多个模块的代码合并到一个函数作用域中来减少输出大小。
//启用 Scope Hoisting
//在 Webpack 4+ 中,Scope Hoisting 默认是启用的,当使用 optimization.concatenateModules 配置项时。你不需要显式地启用它,但你可以通过调整该配置项来影响其行为。
// webpack.config.js  
module.exports = {  
  // ... 其他配置  
  optimization: {  
    concatenateModules: true, // 启用 Scope Hoisting  
    // ... 其他优化选项  
  },  
  module: {  
    rules: [  
      // ... 其他 loader 配置  
    ],  
  },  
};

6、npm打包时需要注意哪些?如何利用webpack来更好的构建?

Npm是目前最大的 JavaScript 模块仓库,里面有来自全世界开发者上传的可复用模块。

你可能只是JS模块的使用者,但是有些情况你也会去选择上传自己开发的模块。 

关于NPM模块上传的方法可以去官网上进行学习,这里只讲解如何利用webpack来构建。

NPM模块需要注意以下问题:

  1. 要支持CommonJS模块化规范,所以要求打包后的最后结果也遵守该规则。

  2. Npm模块使用者的环境是不确定的,很有可能并不支持ES6,所以打包的最后结果应该是采用ES5编写的。并且如果ES5是经过转换的,请最好连同SourceMap一同上传。

  3. Npm包大小应该是尽量小(有些仓库会限制包大小)

  4. 发布的模块不能将依赖的模块也一同打包,应该让用户选择性的去自行安装。这样可以避免模块应用者再次打包时出现底层模块被重复打包的情况。

  5. UI组件类的模块应该将依赖的其它资源文件,例如.css文件也需要包含在发布的模块里。

7、前端为什么要进行打包和构建?

代码层面:

  1. 体积更小(Tree-shaking、压缩、合并),加载更快

  2. 编译高级语言和语法(TS、ES6、模块化、scss)

  3. 统一、高效的开发环境

  4. 统一的构建流程和产出标准

  5. 集成公司构建规范(提测、上线)

研发流程层面:

  • 统一、高效的开发环境

  • 统一的构建流程和产出标准

  • 集成公司构建规范(提测、上线)

8、webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全!!!很重要

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;

  • 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;

  • 确定入口:根据配置中的 entry 找出所有的入口文件;

  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;

  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;

  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;(在 Compiler 开始生成文件前,钩子 emit 会被执行,这是我们修改最终文件的最后一个机会)

  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

9、怎么配置单页应用?怎么配置多页应用?

单页应用可以理解为webpack的标准模式,直接在entry中指定单页应用的入口即可,这里不再赘述。

多页应用的话,可以使用webpack的 AutoWebPlugin来完成简单自动化的构建,但是前提是项目的目录结构必须遵守他预设的规范。多页应用中要注意的是:

  • 每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了同一套css样式表

  • 随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加新页面还需要修改构建配置

10、Loader机制的作用是什么?常用loader?

机制:webpack默认只能打包js文件,配置里的module.rules数组配置了一组规则,告诉 Webpack 在遇到哪些文件时使用哪些 Loader 去加载和转换打包成js

注意:use属性的值需要是一个由 Loader 名称组成的数组,Loader 的执行顺序是由后到前的;因此, use: ['style-loader', 'css-loader'], // 使用style-loader应该放在css-loader的前面。
每一个 Loader 都可以通过 URL querystring 的方式传入参数,例如css-loader?minimize中的minimize告诉css-loader要开启 CSS 压缩。

常用loader:

css-loader读取 合并CSS 文件
style-loader把 CSS 内容注入到 JavaScript 里
sass-loader 解析sass文件(安装sass-loader,node-sass)
postcss-loader自动添加浏览器兼容前缀(postcss.config配置)
url-loader将文件转换为base64 URI。
vue-loader处理vue文件。

11、Plugin(插件)的作用是什么?常见plugin?

Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性。

Webpack 是通过plugins属性来配置需要使用的插件列表的。plugins属性是一个数组,里面的每一项都是插件的一个实例,在实例化一个组件时可以通过构造函数传入这个组件支持的配置属性。

常见plugin:
compression-webpack-plugin这个插件用于gzip压缩,启用gzip压缩可以大幅缩减传输资源大小,从而缩短资源下载时间,减少首次白屏时间,提升用户体验。compression-webpack-plugin压缩的主要是webpack打包好的资源文件

uglifyjs-webpack-pluginWebpack早期版本的默认JS压缩插件。需要注意的是,uglifyjs-webpack-plugin对ES6的压缩支持可能不是特别好。

terser-webpack-plugin从Webpack 4.0开始,默认使用terser-webpack-plugin作为JS压缩插件。与uglifyjs-webpack-plugin相比,terser-webpack-plugin对ES6的压缩支持更好。同时,可以开启parallel参数,使用多进程进行压缩,加快压缩速度。

ParallelUglifyPlugin:这个插件可以开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成。每个子进程通过UglifyJS去压缩代码,但变为并行执行,从而提高压缩效率。

html-webpack-plugin:自动在打包结束后生成html文件,并引入bundle.js
cleanwebPackPlugin打包自动删除上次打包文件

ExtractTextPlugin插件的作用

ExtractTextPlugin插件的作用是提取出 JavaScript 代码里的 CSS 到一个单独的文件

对此你可以通过插件的filename属性,告诉插件输出的 CSS 文件名称是通过[name]_[contenthash:8].css字符串模版生成的,里面的[name]代表文件名称,[contenthash:8]代表根据文件内容算出的8位 hash 值, 还有很多配置选项可以在ExtractTextPlugin的主页上查到。

new ExtractTextPlugin({
      filename: utils.assetsPath('css/[name].[contenthash].css'),
      allChunks: true
    }),

Webpack loader和plugin区别?重点!!!

1、功能不同。

Loader:Webpack 中的 Loader 主要用于处理文件类型的转换和处理,比如将 ES6/ES7 代码转换成 ES5 代码,将 LESS/SASS/CSS 文件转换成浏览器可识别的 CSS 文件等。

Plugin:Webpack 中的 Plugin 主要用于在打包过程中做一些额外的处理工作,比如文件压缩、代码分离、资源优化、生成 HTML 文件等。

2、使用方式不同

Loader:Webpack 中的 Loader 需要在模块的 rules 属性中配置,同时还需要通过 npm 安装相应的 Loader,如 babel-loader、css-loader 等。在配置 Loader 时,需要设置 Loader 的匹配规则和转换规则,使得 Webpack 能够正确地识别和处理需要转换的文件类型。

Plugin:Webpack 中的 Plugin 需要在配置文件中单独引入,并通过 new 关键字实例化,如 new HtmlWebpackPlugin()、new UglifyJsPlugin() 等。在配置 Plugin 时,需要设置插件的参数和执行顺序,以便插件能够按照开发者的需求进行工作。

3、作用范围不同

Loader:Webpack 中的 Loader 是针对于每个文件进行处理的,每个文件都会经过 Loader 进行转换处理,因此 Loader 的作用范围比较小。

Plugin:Webpack 中的 Plugin 是针对于整个项目进行处理的,它们能够修改 Webpack 打包的结果、优化打包过程、生成文件等,因此 Plugin 的作用范围比较大。

12、什么是bundle,什么是chunk,什么是module?他们之间的关系?sourceMap是干嘛的?

bundle:Bundle是webpack最终输出的文件,它是由一组已经经过加载和编译的Chunk组成的。换句话说,Chunk经过进一步的处理和优化后,最终会被合并成Bundle。Bundle是可以在浏览器中直接运行的代码。

在前端开发中,Bundle的作用是将多个源文件(如JavaScript、CSS、图像等)合并为单个文件,以便在浏览器中更高效地加载和传输。这有助于减少网络请求次数、提高加载速度、实现更好的缓存和压缩效果。

chunk:Chunk是webpack打包过程中的中间产物。它代表着一组被合并在一起的Modules。通常情况下,Chunk是由多个Module组成的,webpack会根据一定的规则将这些Module打包成一个Chunk。

Chunk的产生途径包括:entry入口、异步加载模块和代码分割(code splitting)。Chunk是webpack打包过程中的一个阶段,它表示了模块打包的初步结果。

module:是开发中的单个模块。

他们之间的关系:

  1. **Module(模块)**是webpack中最小的单元,它们是代码的离散功能块。
  2. **Chunk(代码块)**是webpack打包过程中的中间产物,由多个Module组成。
  3. **Bundle(捆绑包)**是webpack最终输出的文件,由一组已经过加载和编译的Chunk组成,可以直接在浏览器中运行。大多数情况下chunk和bundle是一对一的,如果配置了sourcemap时,可能会出现一个chunk对应多个bundle的情况。

sourceMap:是一个映射关系,将打包后的文件隐射到源代码,用于定位报错位置。

配置方式:

例如:devtool:‘source-map’

module.exports = {  
  entry: './src/index.js', // 入口文件  
  output: {  
    filename: 'main.js', // 输出文件名  
    path: path.resolve(__dirname, 'dist'), // 输出目录  
  },  
  devtool: 'source-map', // 开启 source map  
  module: { 
  },

}


加不同前缀意义:

  • inline:不生成映射关系文件,打包进main.js

  • cheap: 1.只精确到行,不精确到列,打包速度快 2.只管业务代码,不管第三方模块

  • module:不仅管业务代码,而且管第三方代码

  • eval:执行效率最快,性能最好

最佳实践:
开发环境:cheap-module-eval-source-map
线上环境:cheap-mudole-source-map

13、HMR热模块更新?

HMR热模块更新:借助webpack.HotModuleReplacementPlugin(),devServer开启hot

devtool: config.dev.devtool,

  // these devServer options should be customized in /config/index.js
  devServer: {
    clientLogLevel: 'warning',
    historyApiFallback: {
      rewrites: [{
        from: /.*/,
        to: path.posix.join(config.dev.assetsPublicPath, 'index.html')
      }]
    },
    hot: true,

场景1:实现只刷新css,不影响js

import './styles.css';

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 在 plugins 中添加
new MiniCssExtractPlugin({
  filename: 'styles.css',
}),

场景2:js中实现热更新,只更新指定js模块


if (module.hot) {
  module.hot.accept(’./library.js’, function() {
    // Do something with the updated library module…
  });
}

webpack模块热更新总结:

  • 通过webpack-dev-server创建两个服务器:提供静态资源的服务(express)和Socket服务
  • express server 负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
  • socket server 是一个 websocket 的长连接,双方可以通信
  • 当 socket server 监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk)
  • 通过长连接,socket server 可以直接将这两个文件主动发送给客户端(浏览器)
  • 浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新

14、babel 相关: polyfill 以及 runtime 区别, ES stage 含义,preset–env 作用等等

1.polyfill 以及 runtime 区别

babel-polyfill 的原理是当运行环境中并没有实现的一些方法,babel-polyfill会做兼容。

babel-runtime 它是将es6编译成es5去执行。我们使用es6的语法来编写,最终会通过babel-runtime编译成es5.也就是说,不管浏览器是否支持ES6,只要是ES6的语法,它都会进行转码成ES5.所以就有很多冗余的代码。

babel-polyfill 它是通过向全局对象和内置对象的prototype上添加方法来实现的。比如运行环境中不支持Array.prototype.find 方法,引入polyfill, 我们就可以使用es6方法来编写了,但是缺点就是会造成全局空间污染。

babel-runtime: 它不会污染全局对象和内置对象的原型,比如说我们需要Promise,我们只需要import Promise from 'babel-runtime/core-js/promise'即可,这样不仅避免污染全局对象,而且可以减少不必要的代码。

2.stage-x:指处于某一阶段的js语言提案

Stage 0 - 设想(Strawman):只是一个想法,可能有 Babel插件。
Stage 1 - 建议(Proposal):这是值得跟进的。
Stage 2 - 草案(Draft):初始规范。
Stage 3 - 候选(Candidate):完成规范并在浏览器上初步实现。
Stage 4 - 完成(Finished):将添加到下一个年度版本发布中。

3. 理解 babel-preset-env

babel-preset-es2015: 可以将es6的代码编译成es5.
babel-preset-es2016: 可以将es7的代码编译为es6.
babel-preset-es2017: 可以将es8的代码编译为es7.
babel-preset-latest: 支持现有所有ECMAScript版本的新特性

15、lazy loading(模块懒加载)

借助import()语法异步引入组件,实现文件懒加载:prefetch,preloading
webpack提倡多写异步代码,提升代码利用率,从而提升页面性能
先加载主业务文件,prefetch利用网络空闲时间,异步加载组件

import(/* webpackPrefetch: true / ‘LoginModal’);

preload和主业务文件一起加载,异步加载组件

import(/ webpackPreload: true */ ‘ChartingLibrary’);

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

长缓存(Long-term Caching)是一种优化网页性能的技术,它能够让浏览器在一段时间内从本地缓存中获取静态文件,而不是每次都从服务器上获取。

在 webpack 中,可以使用 HashedModuleIdsPlugin、NameModulesPlugin 来做到长缓存优化,它可以根据文件内容计算出一个唯一的 hash 值,从而确保文件名称不会发生变化,从而实现长缓存优化。

17、什么是Tree-sharking?

指打包中去除那些引入了但在代码中没用到的死代码。在wepack中js treeshaking通过UglifyJsPlugin来进行,css中通过purify-CSS来进行。

//开启tree-shaking
//package.json 文件中设置 "sideEffects": false

//webpack.config.js
optimization: {  
    usedExports: true, // 启用删除未使用的导出  
    sideEffects: true, // 考虑 sideEffects 来进行 Tree Shaking  
  },  

18、webpack-dev-server 和 http服务器的区别

webpack-dev-server是一个独立的npm模块,同时也是一个服务器插件。在使用webpack-dev-server之前,需要单独安装它作为项目的开发依赖。

Webpack Dev Server插件是一个基于Node.js构建的Web服务器,它可以在本地开发环境中启动一个实时的Web服务器,并且能够自动编译并且刷新浏览器,为前端开发提供了很大的便利。

Webpack Dev Server支持热模块替换(HMR),即在应用程序运行中更新模块而无需刷新整个页面,它还提供了一些其它的特性包括压缩、编译、转换、代码分离等等。Webpack Dev Server通常用来搭建本地开发环境,而部署时则需要使用其它的Web服务器。

而http服务器则因其模拟后台api接口的能力,更适用于测试环境

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

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐