快捷搜索:  汽车  科技

webpack你做过哪些优化(细聊webpack性能优化面面观)

webpack你做过哪些优化(细聊webpack性能优化面面观)「绝对路径和相对路径」都能使用,但是要知道他们之间有一点差异。通过查看当前目录以及祖先路径(即 ./node_modules ../node_modules 等等),相对路径将类似于 Node 查找 'node_modules' 的方式进行查找。「使用绝对路径,将只在给定目录中搜索」。resolve.modules告诉webpack解析时「应该搜索的目录」。参考文档:https://webpack.docschina.org/configuration/resolve/#resolveresolve用来「配置模块如何解析」。例如,现在 ES2015 中调用 import 'lodash',resolve 选项能够对webpack 查找'lodash' 的方式去做修改(查看模块)。// webpack.config.js module.ex

webpack你做过哪些优化(细聊webpack性能优化面面观)(1)

作者: FruitBro

转发链接:https://mp.weixin.qq.com/s/OeNPBVhk5jSKHakqHqUciQ

前言

开发中,webpack文件一般分为3个:

  1. webpack.base.conf.js (基础文件)
  2. webpack.dev.conf.js (开发环境使用的webpack,需要与webpack.base.conf.js结合使用)
  3. webpack.prod.conf.js(上线环境使用的webpack,需要与webpack.base.conf.js结合使用)
一.优化构建速度

webpack在启动后,会根据Entry配置的入口,递归解析所依赖的文件。这个过程分为「搜索文件」「把匹配的文件进行分析、转化」的两个过程,因此可以从这两个角度来进行优化配置。

1.1 缩小文件的搜索范围搜索过程优化方式包括:1. resolve字段告诉webpack怎么去搜索文件,所以首先要重视resolve字段的配置:

参考文档:https://webpack.docschina.org/configuration/resolve/#resolve

resolve用来「配置模块如何解析」。例如,现在 ES2015 中调用 import 'lodash',resolve 选项能够对webpack 查找'lodash' 的方式去做修改(查看模块)。

// webpack.config.js module.exports = { //... resolve: { // configuration options } };

module.export = { resolve: { modules:[path.resolve(__dirname 'node_modules')] extensions: ['.js' '.jsx'] mainfiles: ['index' 'child'], alias: { '@/src': path.resolve(__dirname `../src`) // 当看到@/src这个路径或字符串的时候,实际上指向的是../src目录 } } }

(1). resolve.modules参考文档:https://www.webpackjs.com/configuration/resolve/#resolve-modules

resolve.modules告诉webpack解析时「应该搜索的目录」

「绝对路径和相对路径」都能使用,但是要知道他们之间有一点差异。通过查看当前目录以及祖先路径(即 ./node_modules ../node_modules 等等),相对路径将类似于 Node 查找 'node_modules' 的方式进行查找。「使用绝对路径,将只在给定目录中搜索」

// webpack.config.js module.exports = { //... resolve: { modules: ['node_modules'] // 相对路径写法,会按./node_modules ../node_modules的方式查找 } };

如果你想要添加一个目录到模块搜索目录,此目录优先于 node_modules/搜索:

// webpack.config.js module.exports = { //... resolve: { modules: [path.resolve(__dirname 'src') 'node_modules'] // 绝对路径写法 } };

「因此:设置resolve.modules:[path.resolve(__dirname 'node_modules')]避免层层查找」。(2). resolve.mainFields参考文档:https://www.webpackjs.com/configuration/resolve/#resolve-mainfields

当从 npm包中导入模块时(例如,import * as D3 from "d3"),此选项将决定在 package.jsonU中使用哪个字段导入模块。根据 webpack 配置中指定的 target 不同,默认值也会有所不同。

当target 属性设置为webworker web 或者没有指定,默认值为:

module.exports = { //... resolve: { mainFields: ['browser' 'module' 'main'] } };

对于其他任意的 target(包括 node),默认值为:

module.exports = { //... resolve: { mainFields: ['module' 'main'] } };

例如,考虑任意一个名为 upstream 的 library,其 package.json包含以下字段

{ "browser": "build/upstream.js" "module": "index" }

在我们 import * as Upstream from 'upstream' 时,这实际上会从browser 属性解析文件。在这里 browser属性是最优先选择的,因为它是 mainFields 的第一项。同时,由 webpack 打包的Node.js 应用程序首先会尝试从 module 字段中解析文件。

(3).resolve.alias参考文档:https://www.webpackjs.com/configuration/resolve/#resolve-alias

创建 import 或 require 的别名,来「确保模块引入变得更简」单。例如,一些位于 src/ 文件夹下的常用模块:

{ "browser": "build/upstream.js" "module": "index"}

现在,「替换「在导入时使用相对路径」这种方式」,就像这样:

import Utility from '../../utilities/utility';

你可以这样使用别名:

{ "browser": "build/upstream.js" "module": "index"}

也可以在给定对象的键后的末尾添加 $,以表示精准匹配:

module.exports = { //... resolve: { alias: { xyz$: path.resolve(__dirname 'path/to/file.js') } } };

这将产生以下结果:

import Test1 from 'xyz'; // 精确匹配,所以 path/to/file.js 被解析和导入 import Test2 from 'xyz/file.js'; // 非精确匹配,触发普通解析

PS: 如果你使用了TS 在webpack中使用了resolve.alias,一般需要在tsconfig.json文件中对其进行配置,否则使用alias会导致无法找到相应目录而报错:

// tsconfig.json "compilerOptions": { "paths": { "@/src/*": ["./src/*"] 'Templates': ["./src/templates/"] } }

对庞大的第三方模块设置resolve.alias 使webpack直接使用库的min文件,避免库内解析

(4). resolve.extensions参考文档:https://www.webpackjs.com/configuration/resolve/#resolve-extensions

配置resolve.extensions可以自动解析确定的扩展。合理配置resolve.extensions,以减少文件查找

resolve.extensions默认值:extensions:['.wasm' '.mjs' '.js' '.json'] 当导入语句没带文件后缀时,Webpack会根据extensions定义的后缀列表进行文件查找,所以:

  • 列表值尽量少
  • 频率高的文件类型的后缀写在前面
  • 源码中的导入语句尽可能的写上文件后缀,如require(./data)要写成require(./data.json)

常用写法:

extensions: ['.js' '.json' '.ts' '.tsx' '.scss']2. module.noParse字段告诉Webpack不必解析哪些文件,可以用来排除对非模块化库文件的解析

参考文档:https://webpack.docschina.org/configuration/module/#module-noparse

如Jquery、ChartJS,另外如果使用resolve.alias配置了react.min.js,则也应该排除解析,因为react.min.js经过构建,已经是可以直接运行在浏览器的、非模块化的文件了。noParse值可以是RegExp、[RegExp]、function

// tsconfig.json"compilerOptions": { "paths": { "@/src/*": ["./src/*"] 'Templates': ["./src/templates/"] } }3. 配置loader时,通过test、exclude、include等缩小搜索范围

module.exports = { //... resolve: { alias: { xyz$: path.resolve(__dirname 'path/to/file.js') } }};二.提升开发效率

开发过程中修改代码后,需要自动构建和刷新浏览器,以查看效果。这个过程可以使用Webpack实现自动化,Webpack负责监听文件的变化,DevServer负责刷新浏览器。

2.1 使用自动刷新2.1.1 Webpack监听文件

Webpack可以开启监听:启动webpack时加上--watch参数

https://webpack.js.org/configuration/dev-server/#root

import Test1 from 'xyz'; // 精确匹配,所以 path/to/file.js 被解析和导入import Test2 from 'xyz/file.js'; // 非精确匹配,触发普通解析

但我们想要更丰富的功能:执行npm run dev就会自动打包,并自动打开浏览器,同时可以模拟一些服务器上的特性,此时就要借助WebpackDevServer来实现。

// tsconfig.json"compilerOptions": { "paths": { "@/src/*": ["./src/*"] 'Templates': ["./src/templates/"] } }

配置

devServer:{ port: 8080 // 默认8080 contentBase: './dist' open: true // 自动打开浏览器,并访问服务器地址。file协议不行,不能发送ajax请求 proxy: { './api': 'http://localhost:3000' // 用户访问 /api 这个路径会被转发到 http://localhost:3000,支持跨域代理 } }2.1.2 DevServer刷新浏览器

devServer: { contentBase: config.build.assetsRoot host: config.dev.host port: config.dev.port open: true inline: true hot: true overlay: { warnings: true errors: true } historyApiFallback: { rewrites: [ { from: /^\/index\// to: `http://${config.dev.host}:${config.dev.port}/index.html` } ] } noInfo: true disableHostCheck: true proxy: { // '/user/message': { // target: `http://go.buy.test.mi.com` // changeOrigin: true // secure: false // } } } DevServer刷新浏览器有两种方式:

  1. 向网页中注入代理客户端代码,通过客户端发起刷新
  2. 向网页装入一个iframe,通过刷新iframe实现刷新效果

默认情况下,以及 devserver: {inline:true} 都是采用第一种方式刷新页面。第一种方式DevServer因为不知道网页依赖哪些Chunk,所以会向每个chunk中都注入客户端代码,当要输出很多chunk时,会导致构建变慢。而一个页面只需要一个客户端,所以关闭inline模式可以减少构建时间,chunk越多提升越明显。关闭方式:

  1. 启动时使用webpack-dev-server --inline false
  2. 配置devserver:{inline:false}

关闭inline后入口网址变为http://localhost:8080/webpack-dev-server/另外devServer.compress参数可配置是否采用Gzip压缩,默认为false

2.2 开启模块热替换HMR

模块热替换不刷新整个网页而只重新编译发生变化的模块,并用新模块替换老模块,所以预览反应更快,等待时间更少,同时不刷新页面能保留当前网页的运行状态。原理也是向每一个chunk中注入代理客户端来连接DevServer和网页。开启方式:

webpack-dev-server --hot使用HotModuleReplacementPlugin,比较麻烦

// package.json "scripts": { "start": "webpack-dev-server" }

webpack-dev-server打包后的dist中的内容放到了内存中,加快访问速度

extensions: ['.js' '.json' '.ts' '.tsx' '.scss']

开启后如果修改子模块就可以实现局部刷新,但如果修改的是根JS文件,会整页刷新,原因在于,子模块更新时,事件一层层向上传递,直到某层的文件接收了当前变化的模块,然后执行回调函数。如果一层层向外抛直到最外层都没有文件接收,就会刷新整页。使用 NamedModulesPlugin 可以使控制台打印出被替换的模块的名称而非数字ID,另外同webpack监听,忽略node_modules目录的文件可以提升性能。

三、优化输出质量-压缩文件体积3.1 区分环境--减小生产环境代码体积

代码运行环境分为「开发环境」「生产环境」,代码需要根据不同环境做不同的操作,许多第三方库中也有大量的根据开发环境判断的if else代码,构建也需要根据不同环境输出不同的代码,所以需要一套机制可以在源码中区分环境,区分环境之后可以使输出的生产环境的代码体积减小。Webpack中使用DefinePlugin插件来定义配置文件适用的环境。

3.2 压缩代码-JS、CSS1. 压缩JS:Webpack内置UglifyJS插件、ParallelUglifyPlugin

使用terser-webpack-plugin插件压缩JS代码: 参考文档:https://webpack.js.org/plugins/terser-webpack-plugin/

module:{ noParse:[/jquery|chartjs/ /react\.min\.js$/]}

取代了 UglifyJsPlugin

// 取代 new UglifyJsPlugin(/* ... */)2. 压缩CSS

2.1 mini-css-extract-plugin:https://webpack.js.org/plugins/mini-css-extract-plugin/ 。该插件将CSS提取到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件。它支持CSS和SourceMap的按需加载。它基于新的webpack v4功能(模块类型)构建,并且需要webpack 4才能正常工作。

2.2 optimize-css-assets-webpack-plugin: https://www.npmjs.com/package/optimize-css-assets-webpack-plugin 。主要是用来压缩css文件

{ test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/ loader: 'url-loader' options: { limit: 10000 name: `/fonts/[name].[hash:8].[ext]` }}

2.3 cssnano基于PostCSS,不仅是删掉空格,还能理解代码含义,例如把color:#ff0000 转换成 color:red,css-loader内置了cssnano,只需要使用 css-loader?minimize 就可以开启cssnano压缩。另外一种压缩CSS的方式是使用PurifyCSSPlugin,需要配合 extract-text-webpack-plugin 使用,它主要的作用是可以去除没有用到的CSS代码,类似JS的Tree Shaking。

3.3 使用Tree Shaking剔除JS死代码

参考文档:https://webpack.docschina.org/guides/tree-shaking/

Tree Shaking可以剔除用不上的死代码,它依赖ES6的import、export的模块化语法,最先在Rollup中出现,Webpack 2.0将其引入。适合用于Lodash、utils.js等工具类较分散的文件。它正常工作的前提是代码必须采用ES6的模块化语法,因为ES6模块化语法是静态的(在导入、导出语句中的路径必须是静态字符串,且不能放入其他代码块中)。如果采用了ES5中的模块化,例如module.export = {...}、require( x y )、if (x) { require( './util' ) },则Webpack无法分析出可以剔除哪些代码。

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015模块语法的 静态结构 特性,例如import和 export。这个术语和概念实际上是由 ES2015 模块打包工具 rollup 普及起来的。

webpack 4正式版本扩展了此检测能力,通过package.json的 "sideEffects" 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 "pure(纯的 ES2015 模块)",由此可以安全地删除文件中未使用的部分。

参考文档:https://webpack.docschina.org/guides/tree-shaking/#将函数调用标记为无副作用

注意,所有导入文件都会受到tree shaking 的影响。这意味着,如果在项目中使用类似css-loader 并import 一个 CSS 文件,则需要将其添加到side effect列表中,以免在生产模式中无意中将它删除:

{ "name": "your-project" "sideEffects": [ "./src/some-side-effectful-file.js" "*.css" ] }

参考文档:https://webpack.docschina.org/guides/tree-shaking/#压缩输出结果

通过 import 和 export语法,我们已经找出需要删除的“未引用代码(dead code)”,然而,不仅仅是要找出,还要在 bundle 中删除它们。为此,我们需要将 mode配置选项设置为 production。

webpack.config.js

const path = require('path'); module.exports = { entry: './src/index.js' output: { filename: 'bundle.js' path: path.resolve(__dirname 'dist') } - mode: 'development' - optimization: { - usedExports: true - } mode: 'production' };

注意,也可以在命令行接口中使用 --optimize-minimize 标记,来启用 TerserPlugin。

准备就绪后,然后运行另一个 npm script npm run build,就会看到输出结果发生了改变。

在 dist/bundle.js 中,现在整个 bundle 都已经被 minify(压缩) 和 mangle(混淆破坏),但是如果仔细观察,则不会看到引入 square 函数,但能看到 cube函数的混淆破坏版本(function r(e){return e*e*e}n.a=r)。现在,随着 minification(代码压缩) 和tree shaking,我们的bundle 减小几个字节!虽然,在这个特定示例中,可能看起来没有减少很多,但是,在有着复杂依赖树的大型应用程序上运行 tree shaking时,会对 bundle 产生显著的体积优化。

运行 tree shaking 需要 ModuleConcatenationPlugin。 通过 mode: "production" 可以添加此插件。 如果你没有使用 mode 设置,记得手动添加 ModuleConcatenationPlugin。

参考文档:https://webpack.docschina.org/guides/tree-shaking/#结论

「结论:」我们已经知道,想要使用 tree shaking 必须注意以下几点:

  • 使用 ES2015模块语法(即 import 和 export)。
  • 确保没有 compiler 将 ES2015 模块语法转换为 CommonJS模块(这也是流行的 Babel preset 中 @babel/preset-env 的默认行为 - 更多详细信息请查看 文档)。
  • 该项目package.json 文件中,添加一个"sideEffects" 属性。
  • 通过将 mode选项设置为 production,启用 minification(代码压缩) 和tree shaking。

你可以将应用程序想象成一棵树。绿色表示实际用到的 source code(源码)和 library(库),是树上活的树叶。灰色表示未引用代码,是秋天树上枯萎的树叶。为了除去死去的树叶,你必须摇动这棵树,使它们落下。

四、优化输出质量--加速网络请求4.1 使用CDN加速静态资源加载1. CND加速的原理

CDN通过将资源部署到世界各地,使得用户可以就近访问资源,加快访问速度。要接入CDN,需要把网页的静态资源上传到CDN服务上,在访问这些资源时,使用CDN服务提供的URL。

由于CDN会为资源开启长时间的缓存,例如用户从CDN上获取了index.html,即使之后替换了CDN上的index.html,用户那边仍会在使用之前的版本直到缓存时间过期。业界做法:

  • HTML文件:放在自己的服务器上且关闭缓存,不接入CDN
  • 静态的JS、CSS、图片等资源:开启CDN和缓存,同时文件名带上由内容计算出的Hash值,这样只要内容变化hash就会变化,文件名就会变化,就会被重新下载而不论缓存时间多长。

另外,HTTP1.x版本的协议下,浏览器会对于向同一域名并行发起的请求数限制在4~8个。那么把所有静态资源放在同一域名下的CDN服务上就会遇到这种限制,所以可以把他们分散放在不同的CDN服务上,例如JS文件放在js.cdn.com下,将CSS文件放在css.cdn.com下等。这样又会带来一个新的问题:增加了域名解析时间,这个可以通过dns-prefetch来解决 <link rel='dns-prefetch' href='//js.cdn.com'> 来缩减域名解析的时间。形如**//xx.com 这样的URL省略了协议**,这样做的好处是,浏览器在访问资源时会自动根据当前URL采用的模式来决定使用HTTP还是HTTPS协议。

当浏览器从第三方服务跨域请求资源的时候,在浏览器发起请求之前,这个第三方的跨域域名需要被解析为一个IP地址,这个过程就是DNS解析,DNS缓存可以用来减少这个过程的耗时,DNS解析可能会增加请求的延迟,对于那些需要请求许多第三方的资源的网站而言,DNS解析的耗时延迟可能会大大降低网页加载性能。

参考文章:https://developer.mozilla.org/zh-CN/docs/Web/Performance/dns-prefetch

2. 总之,构建需要满足以下几点:
  • 静态资源导入的URL要变成指向CDN服务的绝对路径的URL
  • 静态资源的文件名需要带上根据内容计算出的Hash值
  • 不同类型资源放在不同域名的CDN上
3. 最终配置:

// package.json"scripts": { "dev": "webpack --watch" // --watch监听打包文件,只要发生变化,就会重新打包。只要有这个参数就生效。}4.2 多页面应用提取页面间公共代码,以利用缓存

  1. 原理

大型网站通常由多个页面组成,每个页面都是一个独立的单页应用,多个页面间肯定会依赖同样的样式文件、技术栈等。如果不把这些公共文件提取出来,那么每个单页打包出来的chunk中都会包含公共代码,相当于要传输n份重复代码。如果把公共文件提取出一个文件,那么当用户访问了一个网页,加载了这个公共文件,再访问其他依赖公共文件的网页时,就直接使用文件在浏览器的缓存,这样公共文件就只用被传输一次。

  1. 应用方法

把多个页面依赖的公共代码提取到common.js中,此时common.js包含基础库的代码

devServer:{ contentBase: './dist' // 服务器起在哪个文件夹下。WebpackDevServer会帮助我们在这个文件夹下起一个服务器}

找出依赖的基础库,写一个base.js文件,再与common.js提取公共代码到base中,common.js就剔除了基础库代码,而base.js保持不变

devServer:{ port: 8080 // 默认8080 contentBase: './dist' open: true // 自动打开浏览器,并访问服务器地址。file协议不行,不能发送ajax请求 proxy: { './api': 'http://localhost:3000' // 用户访问 /api 这个路径会被转发到 http://localhost:3000,支持跨域代理 }}

  1. 得到基础库代码base.js,不含基础库的公共代码common.js,和页面各自的代码文件xx.js。

页面引用顺序如下:base.js--> common.js--> xx.js

4.3 分割代码以按需加载
  1. 原理

单页应用的一个问题在于使用一个页面承载复杂的功能,要加载的文件体积很大,不进行优化的话会导致首屏加载时间过长,影响用户体验。做按需加载可以解决这个问题。具体方法如下:

  • 将网站功能按照相关程度划分成几类
  • 每一类合并成一个Chunk,按需加载对应的Chunk
  • 例如,只把首屏相关的功能放入执行入口所在的Chunk,这样首次加载少量的代码,其他代码要用到的时候再去加载。最好提前预估用户接下来的操作,提前加载对应代码,让用户感知不到网络加载
  1. 做法

一个最简单的例子:网页首次只加载main.js,网页展示一个按钮,点击按钮时加载分割出去的show.js,加载成功后执行show.js里的函数

devServer: { contentBase: config.build.assetsRoot host: config.dev.host port: config.dev.port open: true inline: true hot: true overlay: { warnings: true errors: true } historyApiFallback: { rewrites: [ { from: /^\/index\// to: `http://${config.dev.host}:${config.dev.port}/index.html` } ] } noInfo: true disableHostCheck: true proxy: { // '/user/message': { // target: `http://go.buy.test.mi.com` // changeOrigin: true // secure: false // } } }

「import(/* webpackChunkName:show */ './show').then() 是实现按需加载的关键」,Webpack内置对import( *)语句的支持,Webpack会以./show.js为入口重新生成一个Chunk。代码在浏览器上运行时只有点击了按钮才会开始加载show.js,且import语句会返回一个Promise,加载成功后可以在then方法中获取加载的内容。这要求浏览器支持Promise API,对于不支持的浏览器,需要注入Promise polyfill。/* webpackChunkName:show */ 是定义动态生成的Chunk的名称,默认名称是[id].js,定义名称方便调试代码。为了正确输出这个配置的ChunkName,还需要配置Webpack:

//... output:{ filename:'[name].js' chunkFilename:'[name].js' // 指定动态生成的Chunk在输出时的文件名称 }五、优化输出质量--提升代码运行时的效率5.1 使用Prepack提前求值

  1. 原理:

Prepack是一个部分求值器,编译代码时提前将计算结果放到编译后的代码中,而不是在代码运行时才去求值。通过在便一阶段预先执行源码来得到执行结果,再直接将运行结果输出以提升性能。但是现在Prepack还不够成熟,用于线上环境还为时过早。

参考文档:https://github.com/facebook/prepack

  1. 使用方法

const PrepackWebpackPlugin = require('prepack-webpack-plugin').default; module.exports = { plugins:[ new PrepackWebpackPlugin() ] }5.2 使用Scope Hoisting

  1. 原理

译作“作用域提升”,是在Webpack3中推出的功能,它分析模块间的依赖关系,尽可能将被打散的模块合并到一个函数中,但不能造成代码冗余,所以只有被引用一次的模块才能被合并。由于需要分析模块间的依赖关系,所以源码必须是采用了ES6模块化的,否则Webpack会降级处理不采用Scope Hoisting。

  1. 使用方法

const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin'); //... plugins:[ new ModuleConcatenationPlugin(); ] resolve:{ mainFields:['jsnext:main' 'browser' 'main'] }

webpack --display-optimization-bailout 输出日志中会提示哪个文件导致了降级处理

六、使用输出分析工具

启动Webpack时带上这两个参数可以生成一个json文件,输出分析工具大多依赖该文件进行分析:webpack --profile --json > stats.json 其中--profile 记录构建过程中的耗时信息,--json 以JSON的格式输出构建结果,>stats.json 是UNIX / Linux系统中的管道命令,含义是将内容通过管道输出到stats.json文件中。

  1. 官方工具Webpack Analyse

打开该工具的官网http://webpack.github.io/analyse/上传stats.json,就可以得到分析结果

  1. webpack-bundle-analyzer

可视化分析工具,比Webapck Analyse更直观。使用也很简单:

npm i -g webpack-bundle-analyzer安装到全局 按照上面方法生成stats.json文件 在项目根目录执行webpack-bundle-analyzer,浏览器会自动打开结果分析页面。

推荐JavaScript学习相关文章

《JS实现各种日期操作方法汇总》

《「实践」细聊前端性能优化总结》

《「实践」浏览器中的画中画(Picture-in-Picture)模式及其 API》

《「多图」一文带你彻底搞懂 Web Workers (上)》

《「多图」一文带你彻底搞懂 Web Workers (中)》

《深入细聊前端下载总结「干货」》

《细品西瓜播放器功能分析(上)「实践」》

《细品西瓜播放器功能分析(下)「实践」》

《细聊50道JavaScript基础面试题「附答案」》

《webpack4主流程源码解说以及动手实现一个简单的webpack(上)》

《webpack4主流程源码解说以及动手实现一个简单的webpack(下)》

《细聊前端架构师的视野》

《细聊应用场景再谈防抖和节流「进阶篇」》

《前端埋点统一接入方案实践》

《细聊微内核架构在前端的应用「干货」》

《一种高性能的Tree组件实现方案「干货」》

《进击的JAMStack》

《前后端全部用 JS 开发是什么体验(Hybrid Egg.js经验分享)上》

《前后端全部用 JS 开发是什么体验(Hybrid Egg.js经验分享)中》

《前后端全部用 JS 开发是什么体验(Hybrid Egg.js经验分享)下》

《一文带你搞懂 babel-plugin-import 插件(上)「源码解析」》

《一文带你搞懂 babel-plugin-import 插件(下)「源码解析」》

《JavaScript常用API合集汇总「值得收藏」》

《推荐10个常用的图片处理小帮手(上)「值得收藏」》

《推荐10个常用的图片处理小帮手(下)「值得收藏」》

《JavaScript 中ES6代理的实际用例》

《12 个实用的前端开发技巧总结》

《一文带你搞懂搭建企业级的 npm 私有仓库》

《教你如何使用内联框架元素 IFrames 的沙箱属性提高安全性?》

《细说前端开发UI公共组件的新认识「实践」》

《细说DOM API中append和appendChild的三个不同点》

《细品淘系大佬讲前端新人如何上王者「干货」》

《一文带你彻底解决背景跟随弹窗滚动问题「干货」》

《推荐常用的5款代码比较工具「值得收藏」》

《Node.js实现将文字与图片合成技巧》

《爱奇艺云剪辑Web端的技术实现》

《我再也不敢说我会写前端 Button组件「实践」》

《NodeX Component - 滴滴集团 Node.js 生态组件体系「实践」》

《Node Buffers 完整指南》

《推荐18个webpack精美插件「干货」》

《前端开发需要了解常用7种JavaScript设计模式》

《浅谈浏览器架构、单线程js、事件循环、消息队列、宏任务和微任务》

《了不起的 Webpack HMR 学习指南(上)「含源码讲解」》

《了不起的 Webpack HMR 学习指南(下)「含源码讲解」》

《10个打开了我新世界大门的 WebAPI(上)「实践」》

《10个打开了我新世界大门的 WebAPI(中)「实践」》

《10个打开了我新世界大门的 WebAPI(下)「实践」》

《「图文」ESLint 在中大型团队的应用实践》

《Deno是代码的浏览器,你认同吗?》

《前端存储除了 localStorage 还有啥?》

《Javascript 多线程编程​的前世今生》

《微前端方案 qiankun(实践及总结)》

《「图文」V8 垃圾回收原来这么简单?》

《Webpack 5模块联邦引发微前端的革命?》

《基于 Web 端的人脸识别身份验证「实践」》

《「前端进阶」高性能渲染十万条数据(时间分片)》

《「前端进阶」高性能渲染十万条数据(虚拟列表)》

《图解 Promise 实现原理(一):基础实现》

《图解 Promise 实现原理(二):Promise 链式调用》

《图解 Promise 实现原理(三):Promise 原型方法实现》

《图解 Promise 实现原理(四):Promise 静态方法实现》

《实践教你从零构建前端 Lint 工作流「干货」》

《高性能多级多选级联组件开发「JS篇」》

《深入浅出讲解Node.js CLI 工具最佳实战》

《延迟加载图像以提高Web网站性能的五种方法「实践」》

《比较 JavaScript 对象的四种方式「实践」》

《使用Service Worker让你的 Web 应用如虎添翼(上)「干货」》

《使用Service Worker让你的 Web 应用如虎添翼(中)「干货」》

《使用Service Worker让你的 Web 应用如虎添翼(下)「干货」》

《前端如何一次性处理10万条数据「进阶篇」》

《推荐三款正则可视化工具「JS篇」》

《如何让用户选择是否离开当前页面?「JS篇」》

《JavaScript开发人员更喜欢Deno的五大原因》

《仅用18行JavaScript实现一个倒数计时器》

《图文细说JavaScript 的运行机制》

《一个轻量级 JavaScript 全文搜索库,轻松实现站内离线搜索》

《推荐Web程序员常用的15个源代码编辑器》

《10个实用的JS技巧「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(一)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(二)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(三)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(四)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(五)「值得收藏」》

《细品269个JavaScript小函数,让你少加班熬夜(六)「值得收藏」》

《深入JavaScript教你内存泄漏如何防范》

《手把手教你7个有趣的JavaScript 项目-上「附源码」》

《手把手教你7个有趣的JavaScript 项目-下「附源码」》

《JavaScript 使用 mediaDevices API 访问摄像头自拍》

《手把手教你前端代码如何做错误上报「JS篇」》

《一文让你彻底搞懂移动前端和Web 前端区别在哪里》

《63个JavaScript 正则大礼包「值得收藏」》

《提高你的 JavaScript 技能10 个问答题》

《JavaScript图表库的5个首选》

《一文彻底搞懂JavaScript 中Object.freeze与Object.seal的用法》

《可视化的 JS:动态图演示 - 事件循环 Event Loop的过程》

《教你如何用动态规划和贪心算法实现前端瀑布流布局「实践」》

《可视化的 js:动态图演示 Promises & Async/Await 的过程》

《原生JS封装拖动验证滑块你会吗?「实践」》

《如何实现高性能的在线 PDF 预览》

《细说使用字体库加密数据-仿58同城》

《Node.js要完了吗?》

《Pug 3.0.0正式发布,不再支持 Node.js 6/8》

《纯JS手写轮播图(代码逻辑清晰,通俗易懂)》

《JavaScript 20 年 中文版之创立标准》

《值得收藏的前端常用60余种工具方法「JS篇」》

《箭头函数和常规函数之间的 5 个区别》

《通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events》

《「前端篇」不再为正则烦恼》

《「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能》

《深入细品浏览器原理「流程图」》

《JavaScript 已进入第三个时代,未来将何去何从?》

《前端上传前预览文件 image、text、json、video、audio「实践」》

《深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系》

《推荐13个有用的JavaScript数组技巧「值得收藏」》

《前端必备基础知识:window.location 详解》

《不要再依赖CommonJS了》

《犀牛书作者:最该忘记的JavaScript特性》

《36个工作中常用的JavaScript函数片段「值得收藏」》

《Node H5 实现大文件分片上传、断点续传》

《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》

《【实践总结】关于小程序挣脱枷锁实现批量上传》

《手把手教你前端的各种文件上传攻略和大文件断点续传》

《字节跳动面试官:请你实现一个大文件上传和断点续传》

《谈谈前端关于文件上传下载那些事【实践】》

《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》

《最全的 JavaScript 模块化方案和工具》

《「前端进阶」JS中的内存管理》

《JavaScript正则深入以及10个非常有意思的正则实战》

《前端面试者经常忽视的一道JavaScript 面试题》

《一行JS代码实现一个简单的模板字符串替换「实践」》

《JS代码是如何被压缩的「前端高级进阶」》

《前端开发规范:命名规范、html规范、css规范、js规范》

《【规范篇】前端团队代码规范最佳实践》

《100个原生JavaScript代码片段知识点详细汇总【实践】》

《关于前端174道 JavaScript知识点汇总(一)》

《关于前端174道 JavaScript知识点汇总(二)》

《关于前端174道 JavaScript知识点汇总(三)》

《几个非常有意思的javascript知识点总结【实践】》

《都2020年了,你还不会JavaScript 装饰器?》

《JavaScript实现图片合成下载》

《70个JavaScript知识点详细总结(上)【实践】》

《70个JavaScript知识点详细总结(下)【实践】》

《开源了一个 JavaScript 版敏感词过滤库》

《送你 43 道 JavaScript 面试题》

《3个很棒的小众JavaScript库,你值得拥有》

《手把手教你深入巩固JavaScript知识体系【思维导图】》

《推荐7个很棒的JavaScript产品步骤引导库》

《Echa哥教你彻底弄懂 JavaScript 执行机制》

《一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧》

《深入解析高频项目中运用到的知识点汇总【JS篇】》

《JavaScript 工具函数大全【新】》

《从JavaScript中看设计模式(总结)》

《身份证号码的正则表达式及验证详解(JavaScript,Regex)》

《浏览器中实现JavaScript计时器的4种创新方式》

《Three.js 动效方案》

《手把手教你常用的59个JS类方法》

《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》

《深入浅出讲解 js 深拷贝 vs 浅拷贝》

《手把手教你JS开发H5游戏【消灭星星】》

《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》

《手把手教你全方位解读JS中this真正含义【实践】》

《书到用时方恨少,一大波JS开发工具函数来了》

《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》

《手把手教你JS 异步编程六种方案【实践】》

《让你减少加班的15条高效JS技巧知识点汇总【实践】》

《手把手教你JS开发H5游戏【黄金矿工】》

《手把手教你JS实现监控浏览器上下左右滚动》

《JS 经典实例知识点整理汇总【实践】》

《2.6万字JS干货分享,带你领略前端魅力【基础篇】》

《2.6万字JS干货分享,带你领略前端魅力【实践篇】》

《简单几步让你的 JS 写得更漂亮》

《恭喜你获得治疗JS this的详细药方》

《谈谈前端关于文件上传下载那些事【实践】》

《面试中教你绕过关于 JavaScript 作用域的 5 个坑》

《Jquery插件(常用的插件库)》

《【JS】如何防止重复发送ajax请求》

《JavaScript Canvas实现自定义画板》

《Continuation 在 JS 中的应用「前端篇」》

作者: FruitBro

转发链接:https://mp.weixin.qq.com/s/OeNPBVhk5jSKHakqHqUciQ

猜您喜欢: