关于webpack:深入理解webpack自动刷新浏览器

咱们在日常开发时,有一个须要在开发状态下的优化,就是浏览器能主动显示批改后的代码,而无需咱们手动刷新 1. 主动刷新浏览器为了能实现浏览器主动刷新,须要做两件事件: 监听文件变动主动刷新浏览器1.1 监听文件变动监听文件变动是在webpack模块进行。 1.1.1 形式须要在webpack中开启监听模式,有两种形式(开启监听模式后,能够设置监听相干配置watchOptions): 1. 在webpack配置文件中增加watch:true module.export = { watch: true, watchOptions: { // 不监听的文件或文件夹 ignored: /node_modules/, // 监听到变动产生后会等300ms再去执行动作,避免文件更新太快导致从新编译频率太高 aggregateTimeout: 300, // 判断文件是否发生变化是通过不停的去询问零碎指定文件有没有变动实现的 poll: 1000 }}2. 在执行启动 Webpack 命令时,带上 --watch 参数 1.1.2 原理在 Webpack 中监听一个文件发生变化的原理是定时(可在watchOptions.poll中设置)的去获取这个文件的最初编辑工夫,每次都存下最新的最初编辑工夫,如果发现以后获取的和最初一次保留的最初编辑工夫不统一,就认为该文件产生了变动当发现某个文件产生了变动时,并不会立即通知监听者,而是先缓存起来,收集一段时间(可在watchOptions.aggregateTimeout中设置)的变动后,再一次性通知监听者。避免在编辑代码的过程中可能会高频的输出文字导致文件变动的事件高频的产生1.2 主动刷新浏览器监听到文件变动后须要去刷新浏览器,这部分在webpack-dev-server模块中进行。(在应用 webpack-dev-server 模块去启动 webpack 模块时,webpack 模块的监听模式默认会被开启) 1.2.1 原理主动刷新有三种办法: 借助浏览器扩大去通过浏览器提供的接口刷新往要开发的网页中注入代理客户端代码,通过代理客户端去刷新整个页面。把要开发的网页装进一个 iframe 中,通过刷新 iframe 去看到最新成果。DevServer 反对第2、3种办法,第2种是 DevServer 默认采纳的刷新办法。 2. 模块热更新以上主动刷新是会刷新整个页面,这种形式的毛病就是工夫长,同时不能保留页面的状态。 而模块热更新即可在不刷新整个页面的状况下来实时预览。它只会在代码发生变化时,只编译发生变化的模块,并替换浏览器中的老模块。 2.1 两种形式以下两种形式都能实现模块热替换,区别在于其外部应用的通信形式不同。前者应用webcoket通信,后者应用eventSource通信。 2.1.1 webpack-dev-server1. 开启形式 开启DevServer的模块热替换模式: webpack-dev-server --hot增加HotModuleReplacementPlugin插件2. 原理 ...

December 6, 2020 · 1 min · jiezi

关于webpack:你可能不知道的9条Webpack优化策略

引言webpack的打包优化始终是个陈词滥调的话题,惯例的无非就分块、拆包、压缩等。 本文以我本人的教训向大家分享如何通过一些剖析工具、插件以及webpack新版本中的一些新个性来显著晋升webpack的打包速度和改善包体积,学会剖析打包的瓶颈以及问题所在。 本文演示代码,仓库地址 速度剖析 ????webpack 有时候打包很慢,而咱们在我的项目中可能用了很多的 plugin 和 loader,想晓得到底是哪个环节慢,上面这个插件能够计算 plugin 和 loader 的耗时。 yarn add -D speed-measure-webpack-plugin配置也很简略,把 webpack 配置对象包裹起来即可: const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");const smp = new SpeedMeasurePlugin();const webpackConfig = smp.wrap({ plugins: [ new MyPlugin(), new MyOtherPlugin() ]});来看下在我的项目中引入speed-measure-webpack-plugin后的打包状况:从上图能够看出这个插件次要做了两件事件: 计算整个打包总耗时剖析每个插件和 loader 的耗时状况晓得了具体loader和plugin的耗时状况,咱们就能够“隔靴搔痒”了体积剖析 ????打包后的体积优化是一个能够着重优化的点,比方引入的一些第三方组件库过大,这时就要思考是否须要寻找替代品了。 这里采纳的是webpack-bundle-analyzer,也是我平时工作中用的最多的一款插件了。 它能够用交互式可缩放树形图显示webpack输入文件的大小。用起来十分的不便。 首先装置插件: yarn add -D webpack-bundle-analyzer装置完在webpack.config.js中简略的配置一下: const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;module.exports = { plugins: [ new BundleAnalyzerPlugin({ // 能够是`server`,`static`或`disabled`。 // 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。 // 在“动态”模式下,会生成带有报告的单个HTML文件。 // 在`disabled`模式下,你能够应用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。 analyzerMode: "server", // 将在“服务器”模式下应用的主机启动HTTP服务器。 analyzerHost: "127.0.0.1", // 将在“服务器”模式下应用的端口启动HTTP服务器。 analyzerPort: 8866, // 门路捆绑,将在`static`模式下生成的报告文件。 // 绝对于捆绑输入目录。 reportFilename: "report.html", // 模块大小默认显示在报告中。 // 应该是`stat`,`parsed`或者`gzip`中的一个。 // 无关更多信息,请参见“定义”一节。 defaultSizes: "parsed", // 在默认浏览器中主动关上报告 openAnalyzer: true, // 如果为true,则Webpack Stats JSON文件将在bundle输入目录中生成 generateStatsFile: false, // 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。 // 绝对于捆绑输入目录。 statsFilename: "stats.json", // stats.toJson()办法的选项。 // 例如,您能够应用`source:false`选项排除统计文件中模块的起源。 // 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21 statsOptions: null, logLevel: "info" ) ]}而后在命令行工具中输出npm run dev,它默认会起一个端口号为 8888 的本地服务器:图中的每一块清晰的展现了组件、第三方库的代码体积。 ...

December 4, 2020 · 5 min · jiezi

关于webpack:webpack输出文件分析

打包原理简略讲就是生成ast语法树,依据语法树生成对应的js代码这里仅剖析打包输入的后果,从后果剖析webpack对咱们代码做了啥剖析入口文件// main.js// 通过CommonJS标准导入const show = require('./show.js');// 执行 show 函数show('Webpack');依赖文件// show.js// 操作 DOM 元素,把 content 显示到网页上function show(content) { window.document.getElementById('app').innerText = 'Hello,' + content;}// 通过 CommonJS 标准导出 show 函数module.exports = show;打包后果// bundle.js( // webpackBootstrap 启动函数 // modules 即为寄存所有模块的数组,数组中的每一个元素都是一个函数 function (modules) { // 装置过的模块都寄存在这外面 // 作用是把曾经加载过的模块缓存在内存中,晋升性能 var installedModules = {}; // 去数组中加载一个模块,moduleId 为要加载模块在数组中的 index // 作用和 Node.js 中 require 语句类似 function __webpack_require__(moduleId) { // 如果须要加载的模块曾经被加载过,就间接从内存缓存中返回 if (installedModules[moduleId]) { return installedModules[moduleId].exports; } // 如果缓存中不存在须要加载的模块,就新建一个模块,并把它存在缓存中 var module = installedModules[moduleId] = { // 模块在数组中的 index i: moduleId, // 该模块是否曾经加载结束 l: false, // 该模块的导出值 exports: {} }; // 从 modules 中获取 index 为 moduleId 的模块对应的函数 // 再调用这个函数,同时把函数须要的参数传入 modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // 把这个模块标记为已加载 module.l = true; // 返回这个模块的导出值 return module.exports; } // Webpack 配置中的 publicPath,用于加载被宰割进来的异步代码 __webpack_require__.p = ""; // 应用 __webpack_require__ 去加载 index 为 0 的模块,并且返回该模块导出的内容 // index 为 0 的模块就是 main.js 对应的文件,也就是执行入口模块 // __webpack_require__.s 的含意是启动模块对应的 index return __webpack_require__(__webpack_require__.s = 0); })( // 所有的模块都寄存在了一个数组里,依据每个模块在数组的 index 来辨别和定位模块 [ /* 0 */ (function (module, exports, __webpack_require__) { // 通过 __webpack_require__ 标准导入 show 函数,show.js 对应的模块 index 为 1 const show = __webpack_require__(1); // 执行 show 函数 show('Webpack'); }), /* 1 */ (function (module, exports) { function show(content) { window.document.getElementById('app').innerText = 'Hello,' + content; } // 通过 CommonJS 标准导出 show 函数 module.exports = show; }) ]);// 以上看上去简单的代码其实是一个立刻执行函数,能够简写为如下:(function(modules) { // 模仿 require 语句 function __webpack_require__() { } // 执行寄存所有模块数组中的第0个模块 __webpack_require__(0);})([/*寄存所有模块的数组*/])能够看到bundle.js是一个自执行函数,入参就是main.js和show.js革新后的代码块所形成的数组自执行函数里运行了__webpack_require__这个函数,入参是0,0其实就是代码块数组中对应的入参,示意第一个代码块再来看__webpack_require__函数,首先执行的是缓存判断,通过moduleId判断之前是否曾经加载过,如果加载过,间接返回间接的加载后果exports,mouduleId就是不同代码模块在入参数组中的index而如果没有加载过,则新建一个对象,重要的是这个对象中的exports属性,外面寄存的就是加载模块后,对应模块export进去的货色而后用这个exports作为上下文去执行对应的代码块,传递参数为方才新建的module,module里的exports,以及__webpack_require__这个办法自身而后看到main.js中的require被革新成了__webpack_require__,__webpack_require__(1)代表加载第二个代码块第二个代码块中,定义了show这个办法,而后show会作为module.exports的导出,也就是赋值给了installedModules[0].module.exports,也就是这个导出曾经被缓存起来了,下次再有别的中央用到,会间接被导出这就是webpack大抵的打包思路,将各个独自的模块革新成数组作为入参,传给自执行函数,同时保护一个installedModules记录加载过的模块,利用模块数组中的index作为key值,exports记录导出对象按需加载因为单页利用也会有路由这个概念,在没有切换到对应路由之前,可能并不心愿浏览器对这部分页面的js进行下载,从而晋升首页关上的速度,就波及到一个懒加载,即按需加载的问题webpack的按需加载是通过import(XXX)实现的,import()是一个提案,而webpack反对了它// 异步加载 show.jsimport(/* webpackChunkName: 'show' */ './show').then((module) => { // 执行 show 函数 const show = module.default; show('Webpack');});通过这种形式打包,咱们能够发现最终打包进去的文件分成了两个,bundle.js和show.xxx.js其中/* webpackChunkName: 'show' */是专门正文给webpack看的,为的是指定按需加载的包的名字,同时记得在webpack的配置文件的entry中,配置chunkFilename: '[name].[hash].js',不然这个指定不会失效先来看入口文件,将临时没有用到的函数都暗藏后如下:(function (modules) { // webpackJsonp 用于从异步加载的文件中装置模块 window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) { // ... 先省略 }; // 缓存曾经装置的模块 var installedModules = {}; // 存储每个 Chunk 的加载状态; // 键为 Chunk 的 ID,值为0代表曾经加载胜利 var installedChunks = { 1: 0 }; // 模仿 require 语句,和下面介绍的统一 function __webpack_require__(moduleId) { // ... 省略和下面一样的内容 } // 用于加载被宰割进来的,须要异步加载的 Chunk 对应的文件 __webpack_require__.e = function requireEnsure(chunkId) { // ... 先省略 }; // 加载并执行入口模块,和下面介绍的统一 return __webpack_require__(__webpack_require__.s = 0);})( // 寄存所有没有通过异步加载的,随着执行入口文件加载的模块 [ // main.js 对应的模块 (function (module, exports, __webpack_require__) { // 通过 __webpack_require__.e 去异步加载 show.js 对应的 Chunk __webpack_require__.e('show').then(__webpack_require__.bind(null, 'show')).then((show) => { // 执行 show 函数 show('Webpack'); }); }) ]);能够看到import(xxx).then被替换成了__webpack_require__.e(0).then,__webpack_require__.e(0)返回了一个promise第一个then里相当于执行了__webpack_require__(1),但很显著能够看到自执行函数的入参数组只有一个元素,不存在[1],这个[1]是什么时候被插入的呢看一下__webpack_require__.e的实现__webpack_require__.e = function requireEnsure(chunkId) { // 从下面定义的 installedChunks 中获取 chunkId 对应的 Chunk 的加载状态 var installedChunkData = installedChunks[chunkId]; // 如果加载状态为0示意该 Chunk 曾经加载胜利了,间接返回 resolve Promise if (installedChunkData === 0) { return new Promise(function (resolve) { resolve(); }); } // installedChunkData 不为空且不为0示意该 Chunk 正在网络加载中 if (installedChunkData) { // 返回寄存在 installedChunkData 数组中的 Promise 对象 return installedChunkData[2]; } // installedChunkData 为空,示意该 Chunk 还没有加载过,去加载该 Chunk 对应的文件 var promise = new Promise(function (resolve, reject) { installedChunkData = installedChunks[chunkId] = [resolve, reject]; }); installedChunkData[2] = promise; // 通过 DOM 操作,往 HTML head 中插入一个 script 标签去异步加载 Chunk 对应的 JavaScript 文件 var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.charset = 'utf-8'; script.async = true; script.timeout = 120000; // 文件的门路为配置的 publicPath、chunkId 拼接而成 script.src = __webpack_require__.p + "" + chunkId + ".bundle.js"; // 设置异步加载的最长超时工夫 var timeout = setTimeout(onScriptComplete, 120000); script.onerror = script.onload = onScriptComplete; // 在 script 加载和执行实现时回调 function onScriptComplete() { // 避免内存泄露 script.onerror = script.onload = null; clearTimeout(timeout); // 去查看 chunkId 对应的 Chunk 是否装置胜利,装置胜利时才会存在于 installedChunks 中 var chunk = installedChunks[chunkId]; if (chunk !== 0) { if (chunk) { chunk[1](new Error('Loading chunk ' + chunkId + ' failed.')); } installedChunks[chunkId] = undefined; } }; head.appendChild(script); return promise; };首先判断这个chunkId是否曾经加载过,如果是的话,间接返回一个resolve的promise如果不为空又不为0,阐明正在加载中,这里的installedChunks[chunkId]是一个数组,外面保留着[resovle, reject],是在发动网络申请的时候赋值的如果下面两个判断都没击中,阐明是没有加载过,上面开始结构加载办法,次要是通过jsonp的模式首先新建一个promise,并对installedChunks[chunkId]赋值,把这个promise以及他的resolve和reject保留在外面,这也是下面为什么能够通过判断installedChunks[chunkId]不为空又不为0即正处于申请当中,间接返回数组第三个值,即新建的promise,让后续操作能够在这个promise上进行回调的注册而后前面的办法就是通过结构一个script标签,插入到head中,保障代码能马上被下载,同时定义代码执行结束时的回调,判断是曾经加载了代码,如果加载胜利革除监听等,如果加载失败,抛出异样最初返回这个promise,供内部注册回调而这里通过jsonp加载的代码就是打包分离出来的另一个文件show.xx.js,也就是异步加载的show.js相干的代码webpackJsonp( // 在其它文件中寄存着的模块的 ID ['show'], // 本文件所蕴含的模块 {// show.js 所对应的模块 show: (function (module, exports) { function show(content) { window.document.getElementById('app').innerText = 'Hello,' + content; } module.exports = show; }) });接着看webpackJsonp这个办法是怎么定义的window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) { // 把 moreModules 增加到 modules 对象中 // 把所有 chunkIds 对应的模块都标记成曾经加载胜利 var moduleId, chunkId, i = 0, resolves = [], result; for (; i < chunkIds.length; i++) { chunkId = chunkIds[i]; if (installedChunks[chunkId]) { resolves.push(installedChunks[chunkId][0]); } installedChunks[chunkId] = 0; } for (moduleId in moreModules) { if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; } } while (resolves.length) { resolves.shift()(); } };chunkIds代表本人这个文件的id名,因为动静加载的时候,是利用动静加载的文件名形成script标签进行下载的,这里传入这个id是为了触发后续promise的resolve以及标记模块以及被加载moreModules就是对应的代码模块汇合executeModules 就是加载实现后须要被执行模块的index首先遍历installedChunks,后面提到过installedChunks[chunkId]通过网络下载的时候,回赋予三个值,代表其对应的promise,这里取出第一个resolve,保存起来,同时将加载标记置为0,示意已加载而后遍历动静加载的模块,把代码块塞到modules数组里最初执行之前保留下来的resolve函数,触发__webpack_require__.e(0).then的执行这样动静加载的代码通过结构jsonp进行下载,并且将对应代码传到bundle.js的modules中进行保留,而后在then函数中通过__webpack_require__执行模块,缓存输入这里为了便于了解,有对代码做肯定调整,实在的输入状况,能够通过具体打包输入查看,这里仅形容具体打包思路

December 3, 2020 · 3 min · jiezi

关于webpack:webpack4升5

yarn add webpack@next -D一、改良长久化缓存更好的算法和默认值改良长期缓存更好的tree shaking特点webpack 5 会移除所有废除的个性。为了无障碍的推动,应保障在构建时再无任何的废除正告。mode 必须webpack4=>5node.js 10.13webpack-cli降级到最新plugin 和 loader 降级到最新的可用版本降级废除的配置项- optimization.hashedModuleIds: true ↦ optimization.moduleIds: 'hashed'- optimization.namedChunks: true ↦ optimization.chunkIds: 'named'- optimization.namedModules: true ↦ optimization.moduleIds: 'named'- NamedModulesPlugin ↦ optimization.moduleIds: 'named'- NamedChunksPlugin ↦ optimization.chunkIds: 'named'- HashedModulesPlugin ↦ optimization.moduleIds: 'hashed'- optimization.noEmitOnErrors: false ↦ optimization.emitOnErrors: true- optimization.occurrenceOrder: true ↦ optimization: { chunkIds: 'total-size', moduleIds: 'size' }- optimization.splitChunks.cacheGroups.vendors ↦ optimization.splitChunks.cacheGroups.defaultVendors- Compilation.entries ↦ Compilation.entryDependencies- serve ↦ serve 已被移除,举荐应用 DevServer兼容性node: { Buffer: false, process: false }

November 28, 2020 · 1 min · jiezi

关于webpack:webpack-学习笔记三默认配置

在 webpack 学习笔记:疾速入门的练习中,咱们除了在我的项目中装置了 webpack 和 webpack-cli 以外,没有对 webpack 做任何配置,然而 webpack 仍然帮咱们胜利的打包了我的项目中的 JS 文件。 这是为什么呢?它是怎么晓得要打包 src/index.js 和 src/a.js 这两个文件的呢? 1. webpack 的默认配置当咱们不对 webpack 做任何配置,间接运行打包命令对我的项目进行打包操作时,webpack 理论是采纳了本身的一些默认配置。 在疾速入门的练习中,咱们用到了 webpack 的三个默认配置: 打包入口文件打包进口文件打包模式打包入口文件配置打包入口文件,简略来说就是配置 webpack 要从哪一个文件开始进行打包。 一个前端我的项目中通常都会有很多的文件,webpack 在构建我的项目时须要晓得到底要从哪一个文件开始进行打包。 webpack 默认的打包入口文件就是 src/index.js,之所以还能将 src/a.js 一起打包,是因为 webpack 在打包前还会剖析入口文件中的所有依赖文件,将它们全副加载进来后一起进行打包解决。 咱们能够试着将我的项目中的 src 文件换成其余的名字,例如 public,而后再执行一次打包命令。 从截图中能够看到,打包过程中报错了。而谬误提醒就是说“没有在 webpack-demo 目录中找到 src 文件”,因为 webpack 还是在依照默认配置去找 src/index.js 入口文件。 打包进口文件打包进口文件,简略来说就是 webpack 将我的项目中的代码打包胜利后生成的文件。 webpack 默认的打包进口文件就是 dist/main.js。它会主动在我的项目根目录创立 dist 目录,而后将打包好的 main.js 文件放入其中。 打包模式打包模式,指的就是 webpack 在打包时是采纳“开发模式”还是“生产模式”进行打包。 ...

November 20, 2020 · 1 min · jiezi

关于webpack:webpack-学习笔记webpack-简介

webpack 是什么? 咱们常常会在各种文章中看到对于 webpack 的介绍: webpack 是一个前端资源构建工具,是一个动态模块打包器。然而看完之后咱们通常还是一脸懵逼,官网的形容对于很多 webpack 的初学者来说太过于业余,导致大家并不能真正的理解到 webpack 到底是干什么的。 所以在这篇文章,我尽量用最简略的例子和形容,来给他们解释分明,webpack 到底是什么。 前端资源咱们始终说 webpack 是一个前端资源构建工具,这里提到的“前端资源”,指的并不是什么前端材料、文档、博客等,而是在前端我的项目开发中所须要的 HTML、CSS、JS、图片等资源。前端资源构建,也是针对这些代码资源进行构建。 构建工具那构建又是什么意思呢?咱们代码写好之后,为什么还须要构建呢?咱们来看一下上面这段代码: header { background-color: #cccccc; h1 { color: #3c3c3c; }}这是一段用 less 语法写的款式代码,咱们在 .html 文件中引入并在浏览器中运行该代码:运行后会发现 less 写的款式并没有失效,这是因为浏览器不能解析 less 的语法。 同样的情理,咱们在webpack 学习笔记:疾速入门一章中练习的代码,也是因为浏览器不能解析 ES6 的模块化语法导致浏览器报错。 所以,当咱们在一个我的项目中,应用了这些浏览器不能辨认的语法去写代码时,咱们就须要借助一些工具来帮咱们把代码转换成浏览器可能辨认的语法。 例如:能将 less 转换为 css 的工具,将 ES6 转换为 ES5 的工具。如果还有其余语法的代码,可能还须要更多的工具。 这个时候,前端就提出了一个“构建工具”的概念,意思就是咱们找一个大的工具,将这些小工具的性能都蕴含进来,开发者只须要学习这个大工具的应用就能够了。 而这个大工具,就是“构建工具”,webpack,就是构建工具的一种。 动态模块打包器后面咱们弄清楚了 webpack 是一个前端资源构建工具,那什么又是动态模块打包器呢? 有学过 Vue、React 等前端框架的同学可能会常常看到相似上面这种的代码: // index.js// 引入 js 资源import $ from 'jquery';import './a.js';// 引入款式资源import './b.css';import './c.less';// 引入图片、字体等资源// ...下面代码在一个 index.js 文件中引入了所有的资源,这个 index.js 文件咱们也称之为入口文件。 ...

November 20, 2020 · 1 min · jiezi

关于webpack:webpack-学习笔记快速入门

所谓疾速入门,就是实践这种货色咱们都先不讲,间接进入正题,上手去应用 webpack!然而呢,也只能仅限于入门级的应用,等咱们通过根本应用对 webpack 有个初步印象后,咱们仍然还是须要去从实践从细节去残缺的学习 webpack。 1. 我的项目初始化在本地新建一个空文件夹来作为这次入门练习的我的项目根目录。 在命令行工具(终端)中进入该文件目录,执行以下命令对我的项目进行初始化: npm init -y 该命令会应用默认参数在我的项目根目录中创立出 package.json 文件。 2. 装置 webpack在我的项目根目录中执行以下命令装置 webpack 和 webpack-cli。 npm i --save-dev webpack webpack-cli 3. 创立我的项目代码在我的项目根目录中新建 src/index.js 和 src/a.js 两个文件,代码如下: // src/a.jsexport const name = "有猫饼";console.log('a.js', name);// src/index.jsimport { name } from './a.js';console.log(name); 4. 运行我的项目代码在我的项目根目录创立一个 index.html 文件,将 src/index.js 文件引入。 <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title></head><body> <script src="./src/index.js"></script></body></html>在浏览器中运行 index.html 代码会发现如下报错:报错起因是因为咱们没方法在模块以外的文件中应用 import 的语法。 5. webpack 打包 JS 代码在我的项目根目录中执行以下命令,打包 JS 文件: ...

November 19, 2020 · 1 min · jiezi

关于webpack:前端工程化模块化开发下22

模块化开发后面说了gulp工作流这边当初来讲下模块化开发模块化开发是当下最重要的开发范式模块化只是思维。模块化的演变过程: 文件划分的形式(原始形式齐全靠约定)毛病:1.净化全局作用域2.命名抵触3.无奈治理模块依赖关系2.命名空间形式(放到一个对象,而后再对立应用)3.而后就是AMD和CMD标准(社区逐步提出的标准,历史本章不作为重点讲)而后当初最初就是模块化标准的最佳实际:node.js的CommonJS和eES Modules (官网推出)Es Modules根本个性: 主动采纳严格模式,疏忽"use strict"每个ESM模块都是独自的公有作用域ESM是通过CORS去申请内部js模块 (须要容许CORS资源申请)ESM的script标签会提早执行脚本(不会像失常script标签立刻执行)这里导入的是一个只读性援用,所以模块内部不可更改,多个中央导入,模块外部值变动都会影响导入中央。import 是一个 导入申明,在头部应用,不可呈现在条件中属于是动态阶段确定依赖,能够按需引入依赖项,动静执行,理论执行的时候去模块内取值。和commonjs相互导入反对 export {}是固定语法,不是导出对象 动静导入import()返回一个promsie CommonJS特点: 所有代码都运行在模块作用域,不会净化全局作用域。模块能够屡次加载,然而只会在第一次加载时运行一次,而后运行后果就被缓存了,当前再加载,就间接读取缓存后果。要想让模块再次运行,必须革除缓存。模块加载的程序,依照其在代码中呈现的程序。属于动静加载,一导入会把其余模块导出的货色,整体导入对module对象的形容:1.module.exports属性 module.exports属性示意以后模块对外输入的接口,其余文件加载该模块,实际上就是读取module.exports变量。2.exports变量node为每一个模块提供了一个exports变量(能够说是一个对象),指向 module.exports。这相当于每个模块中都有一句这样的命令 var exports = module.exports; 这样,在对外输入时,能够在这个变量上增加办法。例如  exports.add = function (r){return Math.PI r r};留神:不能把exports间接指向一个值,这样就相当于切断了 exports 和module.exports 的关系。例如 exports=function(x){console.log(x)};一个模块的对外接口,就是一个繁多的值,不能应用exports输入,必须应用 module.exports输入。module.exports=function(x){console.log(x);}; 用阮老师的话来说,这两个不好辨别,那就放弃 exports,只用 module.exports 就好(手动机智)在浏览器咱们是不适宜应用CommonJS标准的,动静读取时查看到这个require模块,而后发申请返回文件,这会程序会卡在那里,这对服务器端不是一个问题,因为所有的模块都寄存在本地硬盘,能够同步加载实现,等待时间就是硬盘的读取工夫。然而,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态。 所以浏览器应用的是ESM,然而因为它是es6的模块,有局部浏览器还不反对

November 17, 2020 · 1 min · jiezi

关于webpack:webpack40

file-loader给图片或者文件一个可拜访的地址outputPath:打包的相对路径publicPath:拜访门路,例如图片的src地址,绝对于html页面而言 Reference:webpack配置文档——publicPath url-loader将图片生成base64编码打包进boundle.js文件中。 如果图片比拟小,则能够应用url-loader打包进js中,缩小一次http申请。如果图片较大,则将图片应用file-loader打包进独自的文件夹中,配置拜访门路拜访。(应用limit:2048来管制)将css进行模块化打包:modules:true应用: postcss-loader主动增加厂商前缀,另需postcss.config.js配置文件,其中装置autoprefixer插件,(babel) HtmlWebpackPlugin在打包完结后主动生成html文件并引入boundle.js文件。 clean-webpack-plugin在每次构建前清理 /dist 文件夹new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),:在watch模式下触发增量构建时不删除index.html文件。 Reference:webpack文档——治理输入 devtool(source-map)论断: 在开发环境举荐应用 devtool: 'cheap-module-eval-source-map', 提醒比拟全,且打包速度比拟快。线上环境举荐应用 devtool: 'cheap-module-source-map'。devtool: 'inline-source-map':将source-map文件通过[data]URL的模式写入打包好的js文件底部。 devtool: 'source-map':打包会生成source-map文件。devtool: 'cheap-inline-source-map': 应用cheap更节约性能,检索谬误只准确到行,不准确到列,且只关怀业务代码。devtool: 'cheap-module-inline-source-map':相比于cheap,增加了module就会将谬误检索准确到第三方模块和loader等。devtool: 'eval':性能最好。将错误代码应用eval()执行,与源文件间接进行映射。 举荐浏览:https://segmentfault.com/a/1190000008315937https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.htmlhttps://www.youtube.com/watch?v=NkVes0UMe9Y 主动编译代码webpack 提供几种可选形式,帮忙你在代码发生变化后主动编译代码:1. webpack watch mode(webpack 察看模式)2. webpack-dev-server3. webpack-dev-middlewaredevServerdevServer打包的文件寄存在内存中而不是磁盘中以晋升打包速度,所以dist目录下没有文件。拜访文件时按门路拜访即可。 HMR热更新对于css而言,style-loader底层曾经配置过 module.hot.accept 配置,所以无需再代码中配置,然而在js文件中,须要以下的配置。 if (module.hot) { module.hot.accept('./print.js', function() { console.log('Accepting the updated printMe module!'); printMe(); })}Reference:https://webpack.docschina.org/concepts/hot-module-replacement/HMR配置 babel-loader将es6代码转化为es5代码,适应各种浏览器的兼容性

November 9, 2020 · 1 min · jiezi

关于webpack:webpack入门

npm init -y 生成packge.json。npm i webpack webpack-cli -D,这时候能够npx webpack打包。packge.json文件script中退出"dev": "webpack --config webpack.config.js"新建webpack.config.js const path = require("path"); // webpack外部办法path组件module.exports = { entry: "./main.js", // 入口文件指定 output: { //进口文件配置 配置进口打包门路 filename: "index.js", //打包后的文件名称 path: path.resolve(__dirname, "dist") //resolve绝对路径引入 }};配置完这2个文件就能够间接 npm run dev打包了4.打包时主动生成index.html npm i -D html-webpack-plugin webpack.config.js中退出 // index.html生成插件const HtmlWebPackPlugin = require("html-webpack-plugin"); module.exports = { plugins: [ new HtmlWebPackPlugin({ filename: "index.html", // 生成打包文件名 template: "./index.html", // 模板门路 minify: { //生产模式能够进行配置 removeAttributeQuotes: true, //删除 html文件双引号 collapseWhitespace: true //折叠控行 }, hash:true, //增加哈希值~~~~ }) ],}5.css模块,css以行内的形式插入到head中npm i -D --save css-loader style-loaderwebpack.config.js中退出 ...

November 3, 2020 · 2 min · jiezi

关于webpack:treeshaking效果探讨

webpack等构建工具提供tree-shaking机制, 利用es6中Module的语法的export和import语法进行动态剖析,对无用代码进行剔除,缩小打包后的代码量.启动webpack的tree-shaking,须要: webpack在v2.0以上开启代码压缩webpack只是标记语句依赖以及是否应用, tree-shaking的具体实现个别是由压缩器提供实现, 如webpack默认的压缩工具 terser-webpack-plug就反对tree-shaking.本文不是探讨如何启用tree-shaking,也不钻研tree shaking的底层原理,只通过案例, 钻研tree-shaking对代码的一些影响. 演示中的webpack的配置为: const path = require('path');module.exports = { mode: 'production', entry: './src/index.js', output: { // filename: 'bundle.js', path: path.join(__dirname, 'dist') }, devtool: 'hidden-source-map',};js压缩器的选项采纳默认, 在源码中增加非凡的符号>>>来查看成果.模块接口没有相互依赖模块中的代码: export var firstName = '>>>Michael';export var lastName = '>>>Jackson';export var year = 1958;export var person = { name: '>>>joyer' };export function log(info) { console.log(`>>>${info}`);}export default function() { console.log('>>>i am default');}在入口文件(src/index.js)中, 如果导入(包含全量导入, 默认导入, 具名导入)但没有应用的话: import { firstName } from './mod1.js';console.log('>>>index.js');整个模块都会被疏忽, 打包后的要害代码: ...

October 25, 2020 · 7 min · jiezi

关于webpack:前端工程化篇三-席卷八荒Webpack基础

字数:8960, 浏览工夫:28分钟,点击浏览原文 尽前行者境地窄,向后看者眼界宽。 ——《格言联璧·持躬类》【前端工程化】系列文章链接: 01 扬帆起航-开发环境02 白璧微瑕-包管理器示例代码仓库:https://github.com/BWrong/dev-tools 申明:本篇文章基于webpack v4.43.0,如依照文中代码执行报错,请先查看依赖版本是否和示例代码仓库中统一。 前言自Web2.0以来,前端技术日益蓬勃发展,前端仔们不再满足于切切页面、写写动画,而是可能做更多"高大上"的事件了。但随着我的项目规模和复杂度的晋升,代码的依赖保护、代码压缩、代码格调审查等与业务无关但又不得不做的事件占据了开发人员越来越多的工夫。那时,这些操作均只能依附开发人员手动来进行解决,耗时耗力,齐全是一个刀耕火种的时代(从前车马很慢,毕生只够爱一个人????)。 起初,NodeJS呈现了,作为一门服务端语言,它领有更加弱小的能力,尤其是解决文件的能力,运行也不再受限于浏览器沙盒,能够间接在终端命令行运行。这些个性正是开发前端工程化的外围需要,所以有人开始借助NodeJS来做那些耗时耗力的工作,属于前端本人的工程化时代初见端倪。 当然,这里咱们的重点是Webpack,所以不会花大量篇幅去讲述前端工程化的发展史,仅仅列出一些比拟有代表性的工具,以致敬这些前浪们 Grunt:基于工作的命令行构建工具,构建工具的先驱。Gulp:管道,流式解决,构建性能比grunt高,配置也比较简单。Browserify:把Commonjs打包成浏览器反对的包。Webpack:模块打包器,通过loader反对泛滥文件类型,反对插件,反对按需加载,提取专用代码等,生态欠缺,目前最风行的打包工具。Rollup:侧重于打包库、SDK,输入成绩体积较小。Parcel:打包速度快,入口反对html,打包时会主动装置须要的插件,人家的口号是技术零配置。snowpack:打包速度快,无需打包工具。在Webpack刚刚进去的时候,那个时候Gulp和Grunt还风华正茂,在网上常常有人拿它们来做比照,其实他们是不同类型的构建工具,不是太具备可比性。 如上图所示,虽说它们都是构建工具,然而Gulp、Grunt更加偏差工作式,所有的操作均需以工作的形式来构建;而Webpack则是模块化的编译计划,它通过依赖剖析,进行模块打包,与它比照的应该是Browserify,Rollup之流。 目前来说,grunt和gulp,曾经功成身退了,当下webpack无疑是最热门、最弱小的打包工具。这都得益于保护团队海纳百川有容乃大的态度,Rollup的tree shaking、Parcel的零配置这些亮点都被webpack排汇了。兴许有的人感觉是剽窃,然而咱们读书人的世界何来剽窃呢。更何况不是这样的话,不是得学更多的工具了,又何来我这一头漆黑靓丽的秀发呢????????? 好了,啰嗦了半天,该进入主题了,接下来,看看webpack官网的定义: At its core, webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph which maps every module your project needs and generates one or more bundles. 译:Webpack 是一个古代 JavaScript 应用程序的动态模块打包器(module bundler),当 webpack 解决应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中蕴含应用程序须要的每个模块,而后将所有这些模块打包成一个或多个 bundle。 这里屡次提到了模块,模块在前端开发中个别指JavaScript的模块化产物,相干的介绍网上也有很多,切实找不到也能够看看鄙人之前的文章再谈JavaScript模块化,这里咱们不再赘述。然而这里Webpack所指的模块不仅仅是JavaScript中的模块,通过Loader,它能够解决任意类型的资源。狭义上来说,在Webpack看来,任意资源都是模块。 ...

October 19, 2020 · 7 min · jiezi

关于webpack:如何编写一个-Webpack-Plugin

前言上次写了 如何编写一个 Webpack Loader,明天来说说如何编写一个 Webpack Plugin。 webpack 外部执行流程一次残缺的 webpack 打包大抵是这样的过程: 将命令行参数与 webpack 配置文件 合并、解析失去参数对象。参数对象传给 webpack 执行失去 Compiler 对象。执行 Compiler 的 run 办法开始编译。每次执行 run 编译都会生成一个 Compilation 对象。触发 Compiler 的 make 办法剖析入口文件,调用 compilation 的 buildModule 办法创立主模块对象。生成入口文件 AST(形象语法树),通过 AST 剖析和递归加载依赖模块。所有模块剖析实现后,执行 compilation 的 seal 办法对每个 chunk 进行整顿、优化、封装。最初执行 Compiler 的 emitAssets 办法把生成的文件输入到 output 的目录中。Plugin 作用按我的了解,Webpack 插件的作用就是在 webpack 运行到某个时刻的时候,帮咱们做一些事件。 在 Webpack 运行的生命周期中会播送出许多事件,Plugin 能够监听这些事件,在适合的机会通过 Webpack 提供的 API 扭转输入后果。 官网解释是: 插件向第三方开发者提供了 webpack 引擎中残缺的能力。应用阶段式的构建回调,开发者能够引入它们本人的行为到 webpack 构建流程中。编写 Pluginwebpack 插件的组成: ...

October 18, 2020 · 2 min · jiezi

关于webpack:webpack核心概念

一,模式mode1,开发模式,development包管理工具的--dev指令,是指包装置在改位子。2,生产模式,production 二,出入口入口:所有资源的被打包的入口文件进口:管制所有入口文件打包后的位子 三,loader四,Plugin

October 17, 2020 · 1 min · jiezi

关于webpack:webpack的cleanwebpackplugin插件报错

1、出错代码const path = require('path')const CleanWebpackPlugin = require('clean-webpack-plugin')// const { CleanWebpackPlugin } = require('clean-webpack-plugin')module.exports = { entry: './input.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'output.bundle.js' }, mode: 'development', plugins: [ new CleanWebpackPlugin() ], module: { rules: [ { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { // limit: 8192 // 阐明小于8192字节也就是8k才会执行 limit: 919200 } } ] } ] }}2、谬误形容 [webpack-cli] TypeError: CleanWebpackPlugin is not a constructor 3、出错起因导入插件语句有误,以及应用有误 ...

October 16, 2020 · 1 min · jiezi

关于webpack:webpack引入moment打包体积过大问题

moment 打包体积很大?在我的项目架构中,引入工夫插件moment打包体积很大,具体是什么起因呢? 在node_modules外面找到moment文件夹,找到文件moment.js文件,在文件外面搜寻loadLocale函数 这个函数会在每次打包的时候主动引入所有语言包,导致体积过大 优化计划在webpack中配置一个IgnorePlugin办法 let webpack = require('webpack');module.exports = { ... plugins: [ new webpack.IgnorePlugin(/\.\/locale/, /moment/), // 疏忽moment的语言包打包 ]}这样所有的语言包都没了,咱们要再应用中文语言包,只须要手动在主文件中引入(个别是在index.js) import 'moment/locale/zh-cn';

October 15, 2020 · 1 min · jiezi

关于webpack:一种小拖大的jssdk加载方案

背景jssdk 是在前端中实现某些业务性能的 JavaScript 函数库,通常由 sdk 的开发者开发结束后,交给业务的页面来引入应用。例如: <head> </head>在一些非凡的场景(例如联盟广告)下,咱们通常须要把一个 jssdk 地址 交付给另外一个团队的页面来引入。 技术计划种子js的实现种子 server端 的实现种子js 并不是一个动态的 js,因为它须要内置一个最新版本的资源映射表。因而他是由 server 端动静来生成的,咱们 server 端能够采纳 Node.js 配合模板引擎来实现。 通过 webpack 插件生成资源配置表通过 webpack loader 生成主js我的项目整体构造

October 11, 2020 · 1 min · jiezi

关于webpack:webpack封装配置详解

utils.js// utils.js文件次要是用来解决各种css loader的,比方css-loader,less-loader等。// 引入path模块const path = require('path')// 引入之前的config模块const config = require('../config')// 引入"extract-text-webpack-plugin"它的作用是打包后将生成的css文件通过link的形式引入到html中,如果不应用这个插件,那么css就打包到<head>的style中const ExtractTextPlugin = require('extract-text-webpack-plugin')// 引入package.jsonconst pkg = require('../package.json')exports.assetsSubDirectory = function (_path) { // 联合config文件的代码能够晓得 当环境为生产环境时 assetsSubDirectory为static开发环境也是static const assetsSubDirectory = progress.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory // path.posix.join()是path.join的一种兼容写法 它的作用是门路的拼接 比方path.posix.join('/aa/s','bb') return path.posix.join(assetsSubDirectory,_path)}// 用来生成Loader的函数,自身能够用在vue-loader的配置上,同时也是为styleLoader函数应用exports.cssLoaders = function(options){ // 如果没有传参就默认空对象 options = options||{} // 配置css-loader,css-loader能够让解决css中的@import或者url() const cssLoader = { loader:'css-loader', options:{ sourceMap:options.sourceMap } } // 配置postcss-loader,次要性能是补全css中的兼容性前缀 比方“-webkit-”等 var postcssLoader = { loader:"postcss-laoder", options:{ sourceMap:options.sourceMap } } // 生成loader的公有办法 function generateLoaders(loader,loaderOptions){ // 参数的usePostCss属性是否为true 是就应用两个loader,否则只应用css-loader const loaders = options.usePostCSS? [cssLoader,postcssLoader]:[cssLoader] if(loader){ // 给generateLoaders传loader参数的话 比方less 或者sass 就将这个loader的配置传入到loaders数组中 loaders.push({ loader:loader+'-loader', // Object.assign()是es6的语法 用来合并对象 options: Object.assign({}, loaderOptions, { sourceMap: options.sourceMap }) }) }// 如果options参数的extract属性为true 即应用extract text plugin 将css抽成独自的文件 否则就将css写进style if(options.extract){ return ExtractTextPlugin.extract({ use:loaders, // vue-style-loader能够了解为vue版的style-loader 它可将css放进style中 fallback:'vue-style-loader' }) }else{ return ['vue-style-loader'].concat('loaders') } } return { // 返回各种loader css:generateLoaders(), postcss:generateLoaders(), less:generateLoaders('less'), sass:generateLoaders('sass',{indentedSyntax:true}), scss:generateLoaders('sass'), stylus:generateLoaders('stylus'), styl:generateLoaders('stylus') }}// 生成开发环境下的loader的配置,应用在(webpack.dev.config.js中)exports.styleLoaders = function(options){ const output = [] // 调用cssLoader办法 返回loaders的对象 const loaders = exports.cssLoaders(options) // 遍历每一个loader 并配置成对应的格局 传给output数组 for(const extension in loaders){ const loader = loaders[extension] output.push({ test:new RegExp('\\.'+extension + '$'), use:loader }) } return output}

October 11, 2020 · 1 min · jiezi

关于webpack:webpack篇插件plugin开发

开发webpack插件须要晓得的几个必要条件: 获取编译器 compiler 对象,通过这个对象能过获取包含config配置,资源文件,编译信息,钩子函数等信息编译阶段的生命周期函数,找到适宜的钩子函数解决对应逻辑返回后果反对同步和异步两种形式获取compiler实例第一步获取 compiler 实例对象: // helloPlugin.jsmodule.exports = class RemoveLogs { constructor(options){ this.options = options } apply(compiler) { console.log(`Hello ${this.options.name}`) }};引入这个脚本,在控制台执行就能看到编译后果了: // webpack.config.jsvar HelloWorldPlugin = require('./helloPlugin.js');module.exports = { // 配置插件 plugins: [new HelloWorldPlugin({ name:"chenwl" })]};生命周期钩子函数通过官网文档 compiler-hooks 能够查看到compiler 提供的钩子函数,也能够间接到 /node_modules/webpack/lib/Compiler.js 查看 同步和异步形式钩子函数能够同步也能够异步的形式解决: module.exports = class SyncPlugin { apply(compiler){ // tap 同步 compiler.hooks.emit.tap("tap", (compilation) => { console.log("***** tap *****") }) // tapAsync 参数cb未调用之前过程会暂停 compiler.hooks.emit.tapAsync("tapAsync", (compilation,cb) => { start(0); function start(index){ console.log(index); if(index<=3){ setTimeout(() => { start(++index); }, 1000); }else{ cb() } } }) // tapPromise 通过promise的形式调用 compiler.hooks.emit.tapPromise("tapPromise", (compilation)=>{ return new Promise((resolve,reject)=>{ console.log("start tap-promise"); setTimeout(()=>{ resolve() },2000) }) }) }}logRemoverPlugin文件编译实现后,去掉console: ...

October 11, 2020 · 3 min · jiezi

关于webpack:webpack篇手写常见loader

loader 是导出为一个函数的 node 模块。该函数在 loader 转换资源的时候调用。给定的函数将调用 loader API,并通过 this 上下文拜访。Webpack的配置离不来 loader,官网也有对于如何编写一个loader的文档介绍,这篇文章会通过手写一些常见的loader,加深对loader的意识,进步工作中的开发效率。 导出loaderloader是一个函数,承受匹配到的文件资源字符串和SourceMap,咱们能够通过批改文件内容的字符串返回给下个一loader解决: module.exports = function(source,map){ return source;}筹备工作为了不便咱们编写loader,咱们先筹备好webpack环境: 生成一份 package.json: npm init -y装置webpack: npm install webpack webpack -D创立webpack.config.js文件,并输出以下内容: // webpack.config.jsconst path = require('path')module.exports = { mode: 'development', entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }}package.json退出scripts命令: "scripts": { "build": "webpack", "dev": "webpack --watch" },配置别名咱们晓得,webpack 默认会到 node_modules 外面找对应的loader,这样不不便咱们调试,咱们能够通过给webpack.config.js增加resolveLoader属性,将loader指向咱们创立的loaders文件夹 ... resolveLoader: { modules: [ path.resolve(__dirname, "node_modules"), path.resolve(__dirname, "./loaders"), ], }... 创立loaders文件夹,外面将寄存咱们本人编写的loader: ...

October 10, 2020 · 2 min · jiezi

关于webpack:实现一个简易版Webpack

之前常常被webpack的配置搞得头大,chunk、bundle和module的关系傻傻分不清,loader和plugin越整越糊涂,优化配置一大堆,项目经理前面催,优化过后慢如龟!明天为了彻底搞明确webpack的构建原理,决定手撕webpack,干一个简易版的webpack进去! 筹备工作在开始之前,还要先理解 ast 形象语法树和了解事件流机制 tapable,webpack 在编译过程中将文件转化成ast语法树进行剖析和批改,并在特定阶段利用tapable提供的钩子办法播送事件,这篇文章 Step-by-step guide for writing a custom babel transformation 举荐浏览能够更好的了解ast。 装置 webpack 和 ast 相干依赖包: npm install webpack webpack-cli babylon @babel/core tapable -D 剖析模板文件webpack默认打包进去的bundle.js文件格式是很固定的,咱们能够尝试新建一个我的项目,在根目录下新建src文件夹和index.js及sum.js: src- index.js- sum.js- base - a.js // module.exports = 'a' - b.js // module.exports = 'b'// sum.jslet a = require("./base/a")let b = require("./base/b")module.exports = function () { return a + b}// index.jslet sum = require("./sum");console.log(sum());同时新建 webpack.config.js 输出以下配置: ...

October 9, 2020 · 4 min · jiezi

关于webpack:AST抽象语法树和Babel插件

AST(Abstract Syntax Tree, AST)形象语法树,能够把代码转译成语法树的表现形式例如上面的代码: var a = 3;a + 5AST形象进去的树结构: Program代表的是根节点 VariableDeclaration变量申明 Identifier 标识符 + Numeric Literal数字字面量BinaryExpression(二项式) Identifier 标识符,operator 二项式运算符,Numeric Literal数字字面量能够到 astexplorer.net 查看AST的解析后果 编译器过程大多数编译器的工作过程能够分为三局部: Parse(解析)Transform(转换)Generate(代码生成) 装置 esprima 来了解编译的过程: npm install esprima estraverse escodegenconst esprima = require('esprima')const estraverse = require('estraverse')const escodegen = require('escodegen')let code = `var a = 3`// Parse(解析)let ast = esprima.parseScript(code);//Transform(转换)estraverse.traverse(ast, { enter(node) { console.log("enter",node.type); }, leave(node) { console.log("leave",node.type); }});// Generate(代码生成)const result = escodegen.generate(ast);Babel 对于 AST 的遍历是深度优先遍历,对于 AST 上的每一个分支 Babel 都会先向下遍历走到止境,而后再向上遍历退出刚遍历过的节点,而后寻找下一个分支。AST 对语法树的遍历是 深度优先遍历,所以会先向下遍历走到止境,而后再向上遍历退出刚遍历过的节点,寻找下一个分支,所以遍历的过程中控制台会打印上面的信息: ...

October 6, 2020 · 3 min · jiezi

关于webpack:代理模式在vue中惰性加载echarts等第三方库

1.根底知识点(1)代理模式先从一个简略的例子动手代理模式。如代码所示 // 留神:如果在node环境下运行程序请装置node-fetch// const fetch=require('node-fetch') // 依据keyword申请数据function request(keyword=''){ return new Promise((resolve,reject)=>{ fetch(`http://example.com/data/${keyword}`) .then(response=> { resolve(response.json()) }) })}// 主体程序async function main(){ let res try{ res=await request('a') }catch(e){ } ..........}通常遇到异步申请的场景中,咱们会把异步申请逻辑写在一个独立的函数外面,如上述代码中的request函数,而后主函数main通过调用request函数获取数据。 但如果该接口的开销比拟大、调用比拟频繁多且查问的条件局部反复,咱们能够在main和request两头加一层缓存代理,在下一次调用时如果传入的参数跟之前统一,则可间接返回之前查问的后果。代码如下所示: // 依据keyword申请数据function request(keyword=''){ return new Promise((resolve,reject)=>{ fetch(`http://example.com/data/${keyword}`) .then(response=> { resolve(response.json()) }) })}// 缓存代理const requestProxy=(function(){ let cache={} return async function(keyword){ if(cache[keyword]) return cache[keyword] else{ cache[keyword]=await request(keyword) return cache[keyword] } }})()// 主体程序async function main(){ let res try{ // 第一次:通过异步获取后果 res=await requestProxy('a') // 第二次:通过缓存获取后果 res=await requestProxy('a') }catch(e){ } ..........}除此以外,代理模式的使用场景也很多,例如在img节点加载好图片之前先加载菊花图,简略来说,先加载菊花图,菊花图加载实现后登程onload回调函数,把img的src设置回本来要加载的图片。 ...

October 1, 2020 · 2 min · jiezi

关于webpack:Webpack-源码分析2-Tapable-与-Webpack-的关联

文章首发于我的博客 https://github.com/mcuking/bl...接着上文 Webpack 源码剖析(1)—— Webpack 启动过程剖析 咱们接下来持续剖析 webpack 的构建流程。 上文结尾处咱们提到了 webpack-cli 最终还是调用了 webpack 提供的 webpack 函数,取得了 compiler 实例对象。那么咱们就从新回到 webpack 包查看下这个 webpack 函数,webpack 函数所在文件是 node_module\webpack\lib\webpack.js 。上面是其中的要害代码: const Compiler = require("./Compiler");...const webpack = (options, callback) => { ... let compiler; if (Array.isArray(options)) { compiler = new MultiCompiler( Array.from(options).map(options => webpack(options)) ); } else if (typeof options === "object") { options = new WebpackOptionsDefaulter().process(options); compiler = new Compiler(options.context); compiler.options = options; ... if (options.plugins && Array.isArray(options.plugins)) { for (const plugin of options.plugins) { if (typeof plugin === "function") { plugin.call(compiler, compiler); } else { plugin.apply(compiler); } } } compiler.hooks.environment.call(); compiler.hooks.afterEnvironment.call(); compiler.options = new WebpackOptionsApply().process(options, compiler); } else { throw new Error("Invalid argument: options"); } if (callback) { ... compiler.run(callback); } return compiler;}有下面的代码咱们能够看到 webpack 函数是通过引入了内部定义好的 Compiler 类,并基于接管到的 options 初始化了一个实例对象(如果 options 是数组,则遍历数组中每个 option,别离初始化 compiler 实例对象),最初调用了 compiler 实例上的 run 办法(如果是 watch 模式则调用 watch 办法)。 ...

September 30, 2020 · 3 min · jiezi

关于webpack:Webpack-源码分析1-Webpack-启动过程分析

文章首发于我的博客 https://github.com/mcuking/bl...本文以 webpack 源码来剖析其外部的工作流程,筹备剖析的版本为 4.41.5。 首先咱们要确认的是 webpack 的执行入口文件,通过查看 node_modules 中 webpack 的 package.json 的 bin 字段(如下),咱们能够晓得入口文件是 bin 文件下的 webpack.js,即 node_modules\webpack\bin\webpack.js。 "bin": { "webpack": "./bin/webpack.js"},剖析 webpack 入口文件:webpack.js文件代码并不多,总共有 171 行,次要分为 6 个局部: 失常执行返回process.exitCode = 0;定义了一个运行某个命令的办法 runCommandconst runCommand = (command, args) => {...};定义了一个判断某个包是否装置的办法 isInstalledconst isInstalled = packageName => { try { require.resolve(packageName); return true; } catch (err) { return false; }};定义了两个 webpack 可用的 CLI:webpack-cli 和 webpack-command。其中 installed 属性就是调用了下面的 isInstalled 办法来计算的。const CLIs = [ { name: "webpack-cli", package: "webpack-cli", binName: "webpack-cli", alias: "cli", installed: isInstalled("webpack-cli"), recommended: true, url: "https://github.com/webpack/webpack-cli", description: "The original webpack full-featured CLI." }, { name: "webpack-command", package: "webpack-command", binName: "webpack-command", alias: "command", installed: isInstalled("webpack-command"), recommended: false, url: "https://github.com/webpack-contrib/webpack-command", description: "A lightweight, opinionated webpack CLI." }];紧接着计算出曾经装置的 CLIconst installedClis = CLIs.filter(cli => cli.installed);而后依据装置 CLI 的数量进行解决if (installedClis.length === 0) {...}else if(installedClis.length === 1) {...}else {...}如果一个都没有装置,则会提醒是否要装置 webpack-cli,如果批准则主动帮你装置;如果装置了其中一个,会间接应用那个;如果装置了俩个,会提醒你删掉其中一个 CLI。 ...

September 30, 2020 · 3 min · jiezi

关于webpack:HMR知识点梳理

HMR是啥?简略来讲就是开发的时候更新代码不必刷新整个页面就能够更新对应的内容,能够进步开发效率 webpack中实现HMR所依赖的api与技术性能点nodejs的监听文件的apihttp://nodejs.cn/api/fs.html#fs_fs_watchfile_filename_options_listener,用于监听文件变动内存文件系统https://github.com/webpack/webpack-dev-middleware/blob/v3.7.0/lib/fs.js#L115,用内存文件系统替换compiler自带的文件系统,能够大大提高效率及时通信,生成新的代码块后被动告诉客户端模块中须要解决HMR的事件,个别在loader中解决,能够参考vue-loader的https://github.com/vuejs/vue-loader/blob/6a05115ddf3ea680ab2b00862b2891da2e98a41c/lib/codegen/hotReload.js,如果对应模块中没有解决HMR的代码,事件会一层层冒泡直至刷新整个页面

September 30, 2020 · 1 min · jiezi

关于webpack:webpack实战入门

webpack 1. webpack 就是一个js程序的打包器,当 webpack 解决应用程序时,它会递归地构建一个依赖关系图3.webpack提供了模块化反对,代码压缩混同,解决js兼容问题,性能优化等个性,进步了开发效率和我的项目的可维护性 2. webpack打包的益处程序员在开发的时候须要更好的代码布局,比方有空格、有换行、有正文、错落有致浏览器望能更快的解析代码,而不是更好的看懂代码。所以Webpack的次要作用就是压缩、优化咱们写的代码,把多余的货色去掉,而后依照浏览器喜爱的格调来编排代码!webpack的应用 1. 新建我的项目空白目录 运行 npm init -y命令 初始化包治理配置文件 package.json2. 新建src源代码目录,将我的项目的源代码放在这个目录下3. 装置webpack npm i webpack webpack-cli -D - 在package.json文件的devDependencies中呈现了装置的webpack和webpack-cli,就代表装置胜利3. 在我的项目的根目录自行创立 webpack.config.js 文件 (所有的配置都写这里)配置前打包操作演示 1. 批改我的项目中的package.json文件增加运行脚本dev如下 "scripts":{ "dev":"webpack" }2. 在演示运行的时候须要初始初始配置打包模式 module.exports = { mode: 'development' // 能够设置为development(开发模式),production(公布模式) } - 如果设置为development则示意我的项目处于开发阶段,不会进行压缩和混同,打包速度会快一些 - 如果设置为production则示意我的项目处于上线公布阶段,会进行压缩和混同,打包速度会慢一些 - scripts节点下的脚本,能够通过npm run运行 如 npm run dev 将会启动webpack进行我的项目打包3. 期待webpack打包结束之后,找到默认的dist门路中生成的main.js文件,将其引入到html页面中。浏览页面查看成果。开始配置 1. 在webpack 4.x 中,默认会将src/index.js 作为默认的打包入口js文件2. 默认会将dist/main.js 作为默认的打包输入js文件// 在webpack.config.js内,咱们须要将所有配置当成一个对象导出 引入node.js 中专门操作门路的模块const path = require('path') module.exports = { ...

September 19, 2020 · 2 min · jiezi

关于webpack:webpack3升级4

webpack3降级4 Cannot read property 'Consumer' of undefined

September 17, 2020 · 1 min · jiezi

关于webpack:实现一个-webpack-loader-和-webpack-plugin

loader官网上的定义: loader 是一个转换器,用于对源代码进行转换。例如 babel-loader 能够将 ES6 代码转换为 ES5 代码;sass-loader 将 sass 代码转换为 css 代码。 个别 loader 的配置代码如下: module: { rules: [ { test: /\.js$/, use: [ // loader 的执行程序从下到上 { loader: path.resolve('./src/loader2.js'), }, { loader: path.resolve('./src/loader1.js'), }, ] } ] },rules 数组蕴含了一个个匹配规定和具体的 loader 文件。 上述代码中的 test: /\.js$/ 就是匹配规定,示意对 js 文件应用上面的两个 loader。 而 loader 的解决程序是自下向上的,即先用 loader1 解决源码,而后将解决后的代码再传给 loader2。 loader2 解决后的代码就是最终的打包代码。 loader 的实现loader 其实是一个函数,它的参数是匹配文件的源码,返回后果是解决后的源码。上面是一个最简略的 loader,它什么都没做: module.exports = function (source) { return source}这么简略的 loader 没有挑战性,咱们能够写一个略微简单一点的 loader,它的作用是将 var 关键词替换为 const: ...

September 11, 2020 · 3 min · jiezi

关于webpack:关于babel的一点学习

1.babel-core当咱们在webpack中应用babel的时候,首先要装置babel-core,这是babel编译库的外围包 npm install babel-core --save-dev2.babel-loader之后,webpack中对js文件,咱们要进行编译,就须要配置,在webpack中,须要用到babel-loader来应用bebel npm install babel-loader --save-dev所以,在webpack.config.js代码中,要这样写: rules: [ { test: /\.js$/, use: { loader: 'babel-loader' }, exclude: '/node_modules/' }]3.babel-preset-xxx(xxx代表很多选项)(1)babel-preset-es2015依照es6规范进行编译,同理,如果依照es7规范进行编译,则装置babel-preset-es2016 (2)babel-preset-env一般来说,如果你想用最新的标准做编译,间接装置babel-preset-env就能够了,它蕴含了 babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017,等价于babel-preset-latest,能够编译所有最新标准中的代码 应用编译规定来配置webpack,在babel-loader中新增配置参数: rules: [ { test: /\.js$/, use: { loader: 'babel-loader', options: { presets: ['env'] //也能够写成presets: ['babel-preset-env'] }, exclude: '/node_modules/' } }]4.babel-polyfillbabel官网上写了很明确一句话,babel只负责对语法进行编译。当咱们写箭头函数,babel会帮你把它编译成一般函数,这没有任何问题,然而,比如说咱们代码里应用了promise,babel打包进去的代码其实还是promise,在低版本浏览器里,promise并不反对,然而babel并不会帮你解决,因为这不是语法编译层面须要做的事件。不转换新的API包含,比方Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象。 于是,如果咱们要让打包进去的代码能兼容低版本浏览器,还要思考到promise,Set这样的新语法低版本浏览器不兼容的问题,这时候babel-polyfill就出场了。你只须要全局装置一下babel-polyfill: npm install --save-dev babel-polyfill而后在我的项目中应用一下它,代码就不存在方才提到的兼容性问题了: import 'babel-polyfill';然而,间接用babel-polyfill会有一些坑,第一个坑是净化全局环境,比如说低版本浏览器没有Set,然而babel-polyfill会在全局变量里加一个Set。再一个问题是,会造成代码冗余,举个例子,多个模块用到Promise,每个模块里都有可能独立存在一个对Promise做兼容性的代码。所以,应用babel-polyfill能够解决兼容性问题,但并不是最佳计划,于是,呈现了babel-plugin-transform-runtime,应用这个插件,就能够解决下面的问题了。 5.babel-plugin-transform-runtime装置: npm install babel-plugin-transform-runtime --save-devnpm install babel-runtime --save-dev更改webpack的配置: rules: [ { test: /\.js$/, use: { loader: 'babel-loader', options: { presets: ['env'], //也能够写成presets: ['babel-preset-env'] plugins: ['transform-runtime'] }, exclude: '/node_modules/' } }].babelrc文件============== ...

September 11, 2020 · 1 min · jiezi

关于webpack:初识webpack40基础原理

前言之前都是应用,没有零碎的残缺的好好学习过一遍webpack的原理,趁现在工作有些闲空,整顿下。增强下记忆什么是webpack?不想放webpack官网那张图,感觉都快看吐了。算了还是斗争把,要不然不好说分明.....官网的哈,看能看出的来,那持续了~~ 分为三个局部左侧: 写我的项目的源代码,源文件左侧有一个入口,最下面的.js一个一个的方格能够了解成一个一个的模块,因为webpack是基于node的,所以能够用模块的概念来辨别文件。箭头的示意➡️一个模块能够依赖多个模块箭头➡️示意他们之间的依赖关系左侧会有很多,后缀的文件是浏览器无奈辨认的。例如:.sass .hbs .cjs所以须要通过webpack 来构建一次打包通过webpack的构建 右侧: 输入浏览器能够正确执行的文件,资源咱们还能够利用webpack来压缩 js 、压缩图片 。所以webpack就是一个模块打包器 webpack装置分为两种装置形式 我的项目装置(举荐) 有些我的项目可能很老,依赖的webpack的版本比拟低。 最新的是webpack4.X; webpack5.x还没有公布全局装置如果是全局装置,版本会固定化。如果是去批改来的版本会抵触,依赖抵触等。所以依据我的项目来装置webpack,会好些。装置:webpacl4.x之后,这两个必须要都装置,webpack和 webpack-cli;不倡议离开装。 创立我的项目之后,现须要npm init一下,之后在装置。初始化一下。这个大家应该都晓得。 npm install webpack webpack-cli -Dwebpack启动webpack4.0公布的时候,有说,反对零配置启动。后果发现,哈哈哈哈哈哈哈哈~~~没啥用。根本用不到我的项目中。 咱们来看下零配置:装置好webpack之后,咱们来创立一个入口文件,index.js 零配置 : 默认入口:./src/index.js如果没有src 上面的index.js 打包是不胜利的。默认进口:输入的目录是 ./dist,输入的资源名称:main.js接下来,启动webpack,启动形式有两种。 第一种启动形式:npx webpack为啥用npx启动我的项目 npm5.2版本,就自带npx这个性能;当初咱们启动的整个我的项目webpack是部分装置的如果全局没有装置webpack,全局执行 webpack 就会报错,command not found。它会去全局环境变量中去寻找。通过npx 启动webpack,它会在以后我的项目下的node_modules/.bin 目录去找它的软连贯,在.bin 目录下找到webpack,去启动它。 来看下,打包好外面都显示了啥? 构建的哈希版本Hash: 096bb4bcb72f81514554执行构建的webpack版本Version: webpack 4.44.1执行构建的时长Time: 217ms结构的内容是什么?// 输入的资源叫main.js// 这个资源是958 bytes// Chunks 是为 0 Built at: 2020-08-25 14:45:08 Asset Size Chunks Chunk Namesmain.js 958 bytes 0 [emitted] main// 这块示意 输入的main.js,是依据./src/index.js文件built而来的Entrypoint main = main.js[0] ./src/index.js 29 bytes {0} [built]正告内容本人百度吧,好吗? 用我小学的英语水平大略就是:环境没有设置:就是生产环境和开发环境没设置。会走一个默认的值,默认值是production(生产模式); ...

September 9, 2020 · 3 min · jiezi

关于webpack:前端开发中常用的webpack优化和相关原理

webpack优化方向对于webpack的优化,通常咱们是划分为开发体验和输入代码品质两方面来思考的 ( 一 )优化开发体验通常是从优化构建速度和应用体验 【开发环境】放大文件的搜寻范畴(loader配置includeexclude、module.noParse疏忽对局部没有采纳的模块话的文件递归解析,resolve modules间接指定第三方模块的门路) 主动刷新(设置watch:true,然而会制动刷新浏览器)热更新(网页不刷新,状态不会失落module.hot) DllPlugin (对于依赖的第三方库打包成动态链接库)【生产环境】优化bable-loader (开启缓存)IgnorePluginnoParsehappyPack (多线程打包)ParallelUglifyPlugin(多线程打包)( 2 )优化输入品质【缩小用户能感知到的加载 工夫,也就是首屏加载工夫】辨别环境压缩代码 (js css 图片)tree-shaking (除去没有用到的代码)提取公共代码 (多线程打包)宰割代码按需加载(多线程打包)CDN减速【晋升晦涩度,也就是晋升代码性能】Scope Hosting(让文件打包更小,运行更快)prepack(编译代码是提前将计算结果放到编译后的代码中,再间接运行后果输入)简析相干原理主动刷新让webpack 开启文件监听模式,只须要把wacth:true,wacthOptions能够设置不监听的文件 文件监听原理文件监听原理,是定时获取这个文件最初编辑的工夫,每次都存下最新的最初编辑工夫,如果发现以后获取和最初一次保留的编辑工夫不统一,认为文件产生了变动多个文件的监听,webpack会从入口文件登程,递归所有依赖文件,将这些依赖文件都退出到监听列表中保留文件和最初的编辑工夫占内存,缩小监听文件数量和升高检测频率主动刷新的原理借助浏览器拓展去通过浏览器提供的接口刷新向开发的网页注入代理客户端代码,通过代理客户端去刷新正个页面热更新劣势实时预览不刷新浏览器,能够保留以后网页的运行状态原理在我的项目中注入一个代理客户端来连贯DevServer和我的项目DevServer在每次批改文件后,会生成一个用于替换老模板的补丁文件hot-update.js结尾,同时浏览器开发者工具也能够看到申请这个补丁包但在编辑main.js的时候会发现整个网页刷新了,起因是在子模块产生更新的时候,更新事件会一层层向上传递,到最外层没有文件接管它,则会刷新网页css文件没有中央接管,然而批改所有的css文件都会触发热更新,起因是在于style-loader会注入接管css的代码DllPlugin对于依赖的第三方库,比方vue,vuex等这些不会批改的依赖,咱们能够让它和咱们本人编写的代码离开打包,这样做的益处是每次更改我本地代码的文件的时候,webpack只须要打包我我的项目自身的文件代码,而不会再去编译第三方库,那么第三方库在第一次打包的时候只打包一次,当前只有咱们不降级第三方包的时候,那么webpack就不会对这些库去打包,这样的能够疾速的进步打包的速度 将我的项目依赖的根底模块抽离进去,打包到一个个独自的动态链接库中当须要导入的模块存在于某个动态链接库中,这个模块不能再被打包,间接再动态链接库中获取我的项目依赖的所有动态链接库都须要被加载bable-loader作用是辨认es6+ 的语法通过js词法解析器进行解析,失去AST,而后进行遍历通过EStree标准生成新的AST,而后通过生成器转换es5代码局部新增的原型办法(peoxy,set)babel是不会转译的须要引入 polyfil解决cacheDirectory,开启缓存,防止之后的每次执行,可能产生的、高性能耗费的Bable从新编译过程happyPack(多过程构建,缩小总构建工夫)在webpack和loader之间多加了一层,webpack到了须要编译某个类型的资源模块之后,将该资源工作解决交给了HappyPack,由它在外部线程池中进行任务调度,调配一个线程调用解决改类型资源的Loader来解决这个资源 如果js和css文件的化,间接再module,rules,use['happyPack/loader?id=css']也能够在 plugins里配置,new HappyPack({id:css}),id标识文件类型默认过程是3个,threads能够设置webpack-parallel-uglify-plugin并行处理多个子工作,多个子工作实现后,再将后果发到主过程中,会开启多个子过程,对多个js文件压缩工作分舵多个子过程去实现,能够删除所有的正文,console.log,提取呈现屡次,然而没有定义成变量的利用动态值 uglifyJS原理,将代码解析成AST语法树,再用各种规定去解决它在pulfgins里new一个 parallel-uglify,uglifyJS配置输入紧凑,和删除所有正文,compress删除console.log一次用到的变量等Tree-shaking实质上是打消我的项目中不必要的代码,摇掉没有应用的模块称为DCE,达到删除无用的代码目标,依赖ES6的模块个性 DCEdead code eliminatiom代码不会被执行,不可达到代码执行的后果不会用到代码只会影响变量(只写不读)ES6模块的特点只能作为模块顶层的预计呈现import的模块名只能是字符串常量对模块的引入是动态剖析的,所以能够在编译的时候判断到底加载了什么代码,分析程序流,判断那些变量为被应用和援用,进而删除代码毛病只对ES6+的模块化语法失效,要在babelrc里敞开babel的模块转换性能js文件里,import 一个资源,而后函数没有被应用,import不会去掉提取公共代码起因:雷同的资源重复加载,节约用户的流量和服务器老本,资源态度导致首加载屏迟缓益处:缩小网络传输量,升高服务器老本怎么提取 所有的页面须要用到的根底库,提取到一个独立的base.js文件(长缓存,动态文件名会附加文件内容计算解决的Hash值,通常不)再找到所有页面依赖的公共局部的代码,提取到common.js中为每个网页都生成独立的文件,不蕴含以上局部,各个页面独自须要的局部代码webpack内置了commonschunkPlugin懒加载(按需加载)将整个网站划分为一个个小性能每个类合并为一个chunk,按需加载对应的chunk不须要加载的用户首次关上网站是须要看到的画面对应的性能,将其放在执行入口所在的chunk中,缩小用户感知的网页加载工夫let TaskBtn = () => import(/ webpackChunkName: 'task-btn' / '@/components/TaskBtn.vue');开启 Scope Hoisting让webpack打包进去的代码文件更小,运行更快 代码体积更小,函数申明语句会产生大量的代码代码在运行时创立的函数作用域变少,内存开销也变小原理:剖析模块之间的依赖关系,尽可能将打散的模块合并到一个函数中,但前提是不能造成冗余的代码,只有援用了一次的模块能力被合并CDN减速内容散发,减速网络传输,放慢资源获取的速度动态资源的文件名须要带上由文件内容算进去的Hash值,以防被缓存不同类型的资源放到不同的域名cdn服务上,以防资源并行加载被阻塞

September 2, 2020 · 1 min · jiezi

关于webpack:webpack中的treeshaking

1.什么是tree-shaking?顾名思义,就是摇树,抖掉一些没用的代码;将一些不可能执行到的代码从文件中去除,达到放大文件体积,优化加载速度的成果 2.webpack中为什么要用es6的模块办法import/export能力tree-shaking?因为tree-shaking依赖于es6模块的动态剖析,通过动态代码的剖析就晓得模块的依赖关系 3.什么是动态代码剖析?简略来说,就是不须要运行代码;所以es6的import/export只能作为模块顶层的语句呈现,模块名称不能够有字符串拼接,不能呈现在条件判断中。。。

August 31, 2020 · 1 min · jiezi

关于webpack:webpack-之开发-source-map

当 webpack 打包源代码时,可能会很难追踪到谬误和正告在源代码中的原始地位。例如,如果将三个源文件(a.js, b.js 和 c.js)打包到一个 bundle(bundle.js)中,而其中一个源文件蕴含一个谬误,那么堆栈跟踪就会简略地指向到 bundle.js。这并通常没有太多帮忙,因为你可能须要精确地晓得谬误来自于哪个源文件。 为了更容易地追踪谬误和正告,JavaScript 提供了 source map 性能,将编译后的代码映射回原始源代码。如果一个谬误来自于 b.js,source map 就会明确的通知你。咱们先来看看不增加此配置,页面报错所指向的源文件问打包后的js文件当初咱们增加上打包之后,再看报错指向的源文件

August 6, 2020 · 1 min · jiezi

关于webpack:webpack配置之resolve

webpack配置之resolve配置extensions作用在导入语句没带文件后缀时,Webpack 会主动带上后缀后去尝试拜访文件是否存在。 extensions: ['.js', '.json','.vue', '.less'] // import引入文件的时候不必加后缀mainFields作用有一些第三方模块会针对不同环境提供几分代码。 例如别离提供采纳 ES5 和 ES6 的2份代码,这2份代码的地位写在  package.json  文件里,如下: { "jsnext:main": "es/index.js",// 采纳 ES6 语法的代码入口文件"main": "lib/index.js" // 采纳 ES5 语法的代码入口文件}Webpack 会依据  mainFields  的配置去决定优先采纳哪份代码, mainFields  默认如下: mainFields: ['browser', 'main'] Webpack 会依照数组里的程序去 package.json  文件里寻找,只会应用找到的第一个。 如果你想优先采纳 ES6 的那份代码,能够这样配置: mainFields: ['jsnext:main', 'browser', 'main']### exforceExtension作用如果配置为 true 所有导入语句都必须要带文件后缀### enforceModuleExtension作用### modules作用通知 webpack 解析模块时应该搜寻的目录。绝对路径和相对路径都能应用,然而要晓得它们之间有一点差别。通过查看当前目录以及先人门路(即 `./node_modules`, `../node_modules` 等等), 相对路径将相似于 Node 查找 'node\_modules' 的形式进行查找。应用绝对路径,将只在给定目录中搜寻。**webpack.config.js**module.exports = { //... resolve: { modules: ['node_modules'],},}; **如果你想要增加一个目录到模块搜寻目录,此目录优先于 **`node_modules/` 搜寻:**webpack.config.js**const path = require('path'); ...

August 6, 2020 · 1 min · jiezi

关于webpack:a-preliminary-understanding-of-webpack

`html-webpack-plugin`: 形容: `webpack`打包时,创立一个 `html` 文件,并把 `webpack` 打包后的动态文件主动插入到这个 `html` 文件当中 装置:yarn add html-webpack-plugin -D 应用示例: ` const HtmlWebpackPlugin = require('html-webpack-plugin') plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', template: 'template.html }) ] ``uglifyjs-webpack-plugin`: 形容:插件用来放大(压缩优化)js文件 装置: yarn add uglifyjs-webpack-plugin -D 应用示例: ` const UglifyJsPlugin = require('uglifyjs-webpack-plugin') optimization: { minimizer: [new UglifyJsPlugin()] } ``clean-webpack-plugin`: 形容:革除打包之后多余的, 不确定的文件 装置:yarn add clean-webpack-plugin -D 应用示例: const { CleanWebpackPlugin } = require('clean-webpack-plugin') plugins: [ new CleanWebpackPlugin() ]`copy-webpack-plugin`: 形容: 动态资源打包原样输入 装置: yarn add copy-webpack-plugin -D 应用示例: const CopyWebpackPlugin = require('copy-webpack-plugin') plugins: [ new CopyWebpackPlugin({ patterns: [ { from: path.join(\_\_dirname, 'assets'), to: 'assets' } ] }) ] `optimize-css-assets-webpack-plugin`: 形容:用于优化或者压缩CSS资源 装置:yarn add optimize-css-assets-webpack-plugin -D 应用示例: ` const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') plugins: [ new OptimizeCssAssetsPlugin() ] ``terser-webpack-plugin`: 形容:用于压缩javascript 装置:yarn add terser-webpack-plugin -D 应用示例: ` const TerserPlugin = require('terser-webpack-plugin') optimization: { minimizer: [new TerserPlugin()] } ` ` 生产环境下(默认配置): optimization: { minimizer: [new TerserPlugin({ terserOptions: { warnings: false, compress: { warnings: false, drop_console: false, dead_code: true, drop_debugger: true }, output: { comments: false, beautify: false }, mangle: true }, parallel: true, sourceMap: false })], }, ``mini-css-extract-plugin`: 形容:将CSS提取为独立的文件的插件 装置:yarn add mini-css-extract-plugin -D 应用示例: ` const MiniCssExtractPlugin = require('mini-css-extract-plugin') module: { rules: [ { test: /\\.(scss|sass|css)$/, use: \[MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'\] } ] } ``webpack-node-externals`: 形容:当在Webpack中捆绑时,它将疏忽node_modules 装置: yarn add webpack-node-externals -D 应用示例: ` const nodeExernals= require('webpack-node-externals') externals: [nodeExernals()] ``热加载`: 应用示例: ` const webpack = require('webpack') plugins: [ new webpack.HotModuleReplacementPlugin() ] ``用于创立编译时 “配置的全局常量”  以不便进行 环境转换`: 应用示例: ` const webpack = require('webpack') plugins: [ new webpack.DefinePlugin({ 'process.env': { `NODE_ENV: (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'prod') ? "'production'" : "'development'"` } }) ] ``webpack-merge`: 形容:webpack合并 装置 yarn add webpack-merge -D 应用示例: ` const webpackMerge = require('webpack-merge') const baseWebackConfig = require('./webpack.config.base') const webpackConfig = webpackMerge(baseWebackConfig, { mode: 'development', devtool: 'eval-source-map', stats: { children: false } }) module.exports = webpackConfig `

August 4, 2020 · 2 min · jiezi

关于webpack:webpack-安装和配置

webpack 根底篇npm 卸载包npm uninstall 包名 npm unistall webpack -g -global 全局示意哪都能用 初始化我的项目 yarn init -y ||npm init -ywebpack 装置webpack4.0装置本地的 webpackyarn add webpack webpack-cli -D||npm install webpack webpack-cli -D-D 示意 development 开发环境webpack 能够进行 0 配置目录构造 src index.js间接运行 npx webpack打包工具 -> 输入后的后果(js 模块)打包(间接 js 的模块化)手动配置 webpack(0配置很弱)[x] 默认配置文件的名字是 webpack.config.js/webpackfile.js 通常应用 webpack.config.jswebpack 是基于 node 编写的有webpack.config.js运行命令就会走咱们本人写的配置--config 来指定webpack运行哪个文件* 开发服务器配置- yarn add webpack-dev-server -D||npm install webpack-dev-server -DdevServer:{ port:3000, #端口号 contentBase:'./dist', #目录 如果没有dist文件夹 会在内存外面主动创立 open:true, #是否主动关上浏览器 progress:true, #显示进度条 compress:true #是否开启gzip压缩 proxy:{ //能够配置跨域 } }* 配置脚本命令 package.json"scripts": { } 这外面配置的命令叫做脚本-- config 指定默认运行文件是哪个"build": "webpack --config webpack.config.js", npm run build = npx webpack 会打包"dev": "webpack-dev-server" npm run dev 会启动一个服务器 默认会关上localhost:8080"start":"npm run dev"这样就能够通过 npm run dev/npm run build 执行相干的命令* 配置进口入口[x]entry 入口 能够是相对路径[x]output 进口 输入path 输入门路 必须是绝对路径 打包过后的文件夹名称filename:打包当前的文件名称module.exports={ entry:'./src/index.js', output:{ path:path.resolve(__dirname,'dist'), filename:'bundle[hash:6].js', publicPath:'http://www.baidu.com' }}间接给文件加 hash 值(避免浏览器缓存)filename:'bundle[hash].js'能够用:前面跟数字设置hash值的长度filename:'bundle[hash:8].js'* 配置打包环境mode 的值 2 个值 development 和production[x] development 开发环境 代码没压缩 有正文[x] production 生产环境 代码压缩 没有正文module.exports={ mode:'development', ...}解决 html 主动引入jsplugin 插件 plugins 插件们 数组[插件1,插件2,插件3]src ...

August 1, 2020 · 7 min · jiezi

关于webpack:webpack-安装-实用

要装 webpack 了 顺便做个教程 webpack 介绍概念:webpack 是一个古代 JavaScript 应用程序的动态模块打包器(module bundler)。当 webpack 解决应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中蕴含应用程序须要的每个模块,而后将所有这些模块打包成一个或多个 bundle。 中文网址:https://www.webpackjs.com英文网址:https://webpack.js.orgwebpack 装置npm init 回车 回车 回车 回车 回车 回车在命令行中打入npm init 之后 始终点回车 点到不能点为止 npm install --sava-dev webpack输出之后 等就能够了。。。如果比拟闲的话 能够关上文件目录 眼巴巴看着它加文件 装插件 ——— 去官网复制 (慈母般的微笑)点它 点它 点它 中文网址:https://www.webpackjs.com 再点中文文档 (英文的也行 反正我看不懂) 再点右边的目录 再创立命令中所需的文件创立 src 文件夹 文件夹里在放入一个空的 inder.html

July 22, 2020 · 1 min · jiezi

关于webpack:Webapck配置详解

webpack 1Webapck 2Webpack之编写⼀个Loader、Plugins和webpack的打包原理剖析Webpack 4玩转 webpack,使你的打包速度晋升 90%跟着"呆妹"来学webpack(根底篇)霖呆呆向你发动了多人学习webpack-构建形式篇(2)霖呆呆的六个自定义Webpack插件详解-自定义plugin篇(3)

July 21, 2020 · 1 min · jiezi

Webpack-打包太慢来试试-Bundleless

简介: Webpack 将各个资源打包整合在一起造成 bundle,当资源越来越多时,打包的过程也将越来越慢。如果咱们不须要打包呢?让浏览器间接加载对应的资源,是否就能够实现质的晋升?本文分享基于浏览器的 ESModule 能力实现 Bundless 本地开发的相干思路、核心技术点和 Vite 的相干实现,以及在阿里供应链 POS 场景下的落地实际。 一 引言Webpack 最后是为了解决前端模块化以及应用 Node.Js 生态的问题而呈现,在过来的 8 年工夫里,Webpack 的能力越来越弱小。 但因为多了打包构建这一层,随着我的项目的增长,打包构建速度越来越慢,每次启动都要期待几十秒甚至几分钟,而后启动一轮构建优化,随着我的项目的进一步增大,构建速度又会升高,陷入一直优化的循环。 在我的项目达到肯定的规模时,基于 Bundle 的构建优化的收益变得越来越无限,无奈实现质的晋升。咱们从另一个角度思考,webpack 之所以慢,次要的起因还是在于他将各个资源打包整合在一起造成 bundle,如果咱们不须要 bundle 打包的过程,间接让浏览器去加载对应的资源,咱们将有可能能够跳出这个循环,实现质的晋升。 在 Bundleless 的架构下,咱们不再须要构建一个残缺的 bundle,同时在批改文件时,浏览器也只须要从新加载单个文件即可。因为没有了构建这一层咱们将可能实现以下的指标: 极快的本地启动速度,只须要启动本地服务。极快的代码编译速度,每次只须要解决单个文件。我的项目开发构建的工夫复杂度始终为 O(1),使得我的项目可能持续保持高效的构建。更加简略的调试体验,不再强依赖 sourcemaps 即可实现稳固的单文件的 debug。基于以上的可能性 Bundleless 将从新定义前端的本地开发,让咱们从新找回前端在 10 年前批改单个文件之后,只须要刷新即可即时失效的体验,同时叠加上前端的 HotModuleReplace 相干技术,咱们能够把刷新也省去,最终实现保留即失效。 实现 Bundleless 一个很重要的根底能力是模块的动静加载能力,这一次要的思路会有两个: System.js 之类的 ES 模块加载器,益处是具备较高的兼容性。间接利用 Web 规范的 ESModule,面向未来,同时整体架构也更加简略。在本地开发过程中兼容性的影响不是特地大,同时 ESModule 曾经笼罩了超过 90% 的浏览器,咱们齐全能够利用 ESModule 的能力让浏览器自主加载须要的模块,从而更加低成本同时面向未来实现 Bundleless。 社区中在近一两年也呈现了很多基于 ESModule 的开发工具,如 Vite、Snowpack、es-dev-server 等。本文将次要分享基于浏览器的 ESModule 能力实现 Bundless 本地开发的相干思路、核心技术点以及 Vite 的相干实现和在供应链 POS 场景下的落地实际。 ...

July 10, 2020 · 3 min · jiezi

揭秘webpack插件的工作原理

webpack系列1:常见 loader 源码简析,以及动手实现一个 md2html-loaderwebpack系列2:揭秘webpack 插件工作原理webpack系列3:webpack 主流程源码阅读以及实现一个 webpack前言通过插件我们可以扩展webpack,在合适的时机通过Webpack提供的 API 改变输出结果,使webpack可以执行更广泛的任务,拥有更强的构建能力。本文将尝试探索 webpack 插件的工作流程,进而去揭秘它的工作原理。同时需要你对webpack底层和构建流程的一些东西有一定的了解。 想要了解 webpack 的插件的机制,需要弄明白以下几个知识点: 一个简单的插件的构成webpack构建流程Tapable是如何把各个插件串联到一起的compiler以及compilation对象的使用以及它们对应的事件钩子。插件基本结构plugins是可以用自身原型方法apply来实例化的对象。apply只在安装插件被Webpack compiler执行一次。apply方法传入一个webpck compiler的引用,来访问编译器回调。 一个简单的插件结构:class HelloPlugin { // 在构造函数中获取用户给该插件传入的配置 constructor(options) {} // Webpack 会调用 HelloPlugin 实例的 apply 方法给插件实例传入 compiler 对象 apply(compiler) { // 在emit阶段插入钩子函数,用于特定时机处理额外的逻辑; compiler.hooks.emit.tap('HelloPlugin', (compilation) => { // 在功能流程完成后可以调用 webpack 提供的回调函数; }) // 如果事件是异步的,会带两个参数,第二个参数为回调函数,在插件处理完任务时需要调用回调函数通知webpack,才会进入下一个处理流程。 compiler.plugin('emit', function (compilation, callback) { // 支持处理逻辑 // 处理完毕后执行 callback 以通知 Webpack // 如果不执行 callback,运行流程将会一直卡在这不往下执行 callback() }) }}module.exports = HelloPlugin安装插件时, 只需要将它的一个实例放到Webpack config plugins 数组里面: ...

June 24, 2020 · 6 min · jiezi

webpack-基础使用技巧

一、什么是webpackwebpack 是前端的一个项目构建工具,它是基于 Node.js 开发出来的一个前端工具; https://www.shangmayuan.com/a/1039b79c72014ad9b298681c.html http://webpack.github.io/ css 二、安装1)全局安装 npm i webpack -g 2)项目根目录安装到项目依赖中 npm i webpack --save-devhtml 三、使用 1)npm init -y 2)npm install jquery -S 3)webpack .\src\main.js .\dist\bundle.js前端 npm i webpack-dev-server -D 把这个工具安装到项目的本地开发依赖vuenpm i html-webpack-plugin -Dnodenpm i style-loader css-loader -Djquerynpm i less -D npm i less-loader -Dwebpacknpm i sass -D npm i sass-loader -D npm i node-sass -Dgit9)npm i babel-core babel-loader babel-plugin-transform-runtime -D npm i babel-preset-env babel-preset-stage-0 -Dgithub ...

June 24, 2020 · 6 min · jiezi

webpack

1、webpack.devServer配置如果要启用webpack代理,则配置如下: webpackConfig.devServer = { hot: true, hotOnly: false, // If true: Enable HMR without page refresh when build failure open: true, // auto open port: 8080, overlay: true, publicPath: '/', proxy: { '(/crmp/admin/**)': { target : 'http://10.6.183.146:8088/', changeOrigin: true, secure: false, // 接受运行在 HTTPS 上,且使用了无效证书的后端服务器 }, }, quiet: true, }proxy中的代理请求地址必须是相对路径,且从相对路径左侧开始匹配,如 (/crmp/admin/xxx)代理的是 http://localhost:8080/crmp/admin/xxx请求路径,代理到后端http://10.6.183.146:8088/crmp/admin/xxx地址。代理后,我们在浏览器网络栏看到的请求地址是:Request URL:http://localhost:8080/crmp/admin/xxx。实际是代理服务器请求了后端接口,再把数据响应给localhost:8080。 2、搭建基于webpack4+vue2.6的多页框架骨架

June 22, 2020 · 1 min · jiezi

自己写的webpack插件用于本地打包后将文件上传至阿里云OSS

该 Webpack 插件用于在本地打包完成后,将打包后的文件上传至 阿里云OSS,并提供上传完成的回调使用安装 webpack-oss-upload-plugin npm install webpack-oss-upload-plugin -D在 webpack config 中使用 const prefix = `${dir}/${projectName}/${version}/`;{ output:{ publicPath: `http://e-package.oss-cn-shanghai.aliyuncs.com/${prefix}` }, plugins: [ new WebpackOssUploadPlugin({ // oss 的配置 oss: { region: 'region', endpoint: 'endpoint', accessKeyId: 'accessKeyId', accessKeySecret: 'accessKeySecret', bucket: 'bucket' }, // 上传后的文件路径为:publicPath/{prefix}/your-file.js prefix, // 上传完成后会调用该回调 onComplete: (complication) => { } }) ]}在 onComplete 的参数暴露了 complication 对象,里面包含当前打包的信息,你可以合理使用它 选项说明 oss: 阿里 oss 配置,region、endpoint、accessKeyId、accessKeySecret、bucket 这些参数是必须的dir:可选项,默认为空数组,数组中的每一项表示上传至 oss 形成的目录名。比如 prefix: a/c/c/,那么上传后你的文件位置是:publicPath/a/b/c/your-file.jsonComplete: 可选项,当 OSS 将所有需要上传的文件上传完成后,会被调用,该方法参数为 complication 对象,里面包含当前打包的信息,你可以合理使用它项目地址github 地址:https://github.com/Vibing/web... ...

June 8, 2020 · 1 min · jiezi

create-react-app-env-环境变量设置

以前搭建脚手架常用cross-env进行环境变量设置。"scripts": { "start": "cross-env REACT_APP_ENV=development node scripts/start.js", "build-dev": "cross-env REACT_APP_ENV=test PUBLIC_URL=/webapps/ai-crm-web node scripts/build.js", "build-uat": "cross-env REACT_APP_ENV=uat PUBLIC_URL=/webapps/ai-crm-web node scripts/build.js", "build": "cross-env REACT_APP_ENV=production PUBLIC_URL=/webapps/ai-crm-web node scripts/build.js", "test": "node scripts/test.js --env=jsdom" },没次都要把相关环境变量写到scripts里面感觉特别冗长。 env.js function env() { if (process.env.REACT_APP_ENV === 'development') { // 本地开发环境 return { ENV: 'development', GETEWAY_BASE: 'https:..', APIROOT: 'https:..', APIVERSION: 'v1.0.0', SSO: { redirect_url: 'https://...', client_id: '', client_secret: '', authorization: '' } } }else if (process.env.REACT_APP_ENV === 'test') { // 线上测试环境 }else{ // 生产环境 }}export default env()虽然有独立的配置文件处理更多环境参数。但是还是希望让代码更简介优雅一些。 ...

June 8, 2020 · 1 min · jiezi

一个webpack入门的大坑

学习webpack打包css的时候,遇到了这个错误: ERROR in ./src/index.css 1:0Module parse failed: Unexpected token (1:0)You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders> .hello{| color: red;| } @ ./src/index.js 1:0-21明明没有任何的错误,却就是报错了,loader的顺序也没错。最后发现,是没有加载config。 解答把package.json的build改为 "build": "webpack --config webpack.config.js",

June 6, 2020 · 1 min · jiezi

webpack-如何同时输出压缩和未压缩的文件

有的时候我们想要同时生成压缩和未压缩的文件,比如我们构建 lib 包的时候,我们希望用户能够使用压缩过后的代码文件作为 cdn 文件,最简单的一个方式就是通过指定环境变量,比如指定 MINIFY,如下: const path = require('path')const isMinify = process.env.MINIFY/** * @type {import('webpack').Configuration} */const config = { entry: { index: './src/index.js' }, output: { filename: isMinify ? '[name].min.js' : '[name].js', path: path.join(__dirname, 'dist') }, devtool: 'cheap-source-map', optimization: { minimize: isMinify ? true : false }}module.exports = config我们在使用的时候通过指定环境变量就可以打包成不同的版本: "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build:min": "MINIFY=1 webpack --config=webpack.config.js", "build": "webpack --config=webpack.config.js" }不过这样的缺点就是我们需要运行两次。 ...

June 5, 2020 · 1 min · jiezi

webpack笔记webpack初识与构建工具发展一

为什么需要构建工具?转换 ES6 语法转换 JSXCSS 前缀补全/预处理器压缩混淆图片压缩前端构建演变之路ant + YUI Toolgruntgulp、fis3webpack、rollup、parcel为什么选择 webpack?社区态丰富配置灵活和插件化扩展官方更新迭代速度快初识webpack,简单的例子入手安装先确保你已经安装了 Node其中检查node是否安装成功,使用node -v;检查npm的版本使用npm -v。创建一个新的项目来开始我们的 webpack 之旅: mkdir webpack-customcd webpack-custom使用 npm init (或者使用npm init-y表示默认配置都选择yes)来创建一个「package.json」文件用于管理项目版本和依赖,然后我们使用 npm安装webpack: npm install webpack webpack-cli -D webpack-cli 是使用 webpack 的命令行工具,在 4.x 版本之后不再作为 webpack 的依赖了,我们使用时需要单独安装这个工具。检查是否安装成功: mac系统:./node_modules/.bin/webpack -v window系统:.node_modules.binwebpack -v 安装成功之后,我们可以在项目的「package.json」文件中看到对应的 webpack 版本依赖: "devDependencies": { "webpack": "^4.43.0", "webpack-cli": "^3.3.11" }构建安装完成之后,我们可以使用 ==npx webpack ==命令来运行项目内安装的 webpack。 其中,我们可以使用如下命令执行一些操作: npx webpack --help:查看 webpack-cli 提供了哪些命令可用npx webpack --version:查看我们安装的版本npx webpack:运行构建我们先添加两个简单的代码文件,「src/index.js」和「src/hello.js」,如代码: index.js代码: import { hello, log } from './hello.js';log(hello);hello.js代码: ...

June 3, 2020 · 1 min · jiezi

VUE引入fontawesome-打包报错-Module-parse-failed-Unexpected-character

将|ttf|eot|woff|woff2加入webpack file-loader配置中

June 2, 2020 · 1 min · jiezi

通过webpack构建library库

构建 librarywebpack 除了打包应用程序代码,还可以用于打包 JavaScript library 应用场景提炼高可服用工具类 code构建 UI 库根据业务需求,在其他 UI 库的基础上做业务组件封装... 兼容性用户应该能够通过以下方式访问 library ES2015 模块import webpackNumbers from 'webpack-numbers' CommonJS 模块require('webpack-numbers') AMDCMD全局变量,当通过 script 脚本引入时Nodejsoutput跟 webpack 打包部署代码最大的不同点就在于 output 输出属性的配置上,webpack 为构建 lib 提供了 library,libraryTarget, libraryExport 等属性 output: { path: path.resolve(__dirname, 'dist'), filename: 'myLib.js', library: 'myLib', // 暴露出去的变量的名字 libraryTarget: 'umd'}library暴露的模块名称。取决于 libraryTarget 的值,当 libraryTarget:commonjs2 时无效 libraryTarget暴露library的方式 变量,以 script 方式引用, 默认值。 node 环境不支持 varassign这两个属性,都是在全局创建一个变量,只有定义与未定义的区别,并不能在 nodejs 中得的支持,并且存在变量冲突的可能性 module.exports = { mode: "production", entry: "./q-library/index.js", output: { path: path.resolve(process.cwd(), "./lib"), filename: "q-library.js", library: "qlibrary", // 模块名称 libraryTarget: "assign", },};输出代码示例 ...

May 30, 2020 · 2 min · jiezi

Webpack如何配置热更新

什么是HMR是指 Hot Module Replacement,缩写为 HMR。对于你需要更新的模块,进行一个"热"替换,所谓的热替换是指在不需要刷新页面的情况下,对某个改动进行无缝更新。如果你没有配置HMR,那么你每次改动,都需要刷新页面,才能看到改动之后的结果,对于调试来说,非常麻烦,而且效率不高,最关键的是,你在界面上修改的数据,随着刷新页面会丢失,而如果有类似Webpack热更新的机制存在,那么,则是修改了代码,不会导致刷新,而是保留现有的数据状态,只将模块进行更新替换。也就是说,既保留了现有的数据状态,又能看到代码修改后的变化。 总结: 加载页面时保存应用程序状态只更新改变的内容,节省调试时间修改样式更快,几乎等同于在浏览器中更改样式依赖package.json: "dependencies": { "css-loader": "^3.2.0", "style-loader": "^1.2.1", "webpack": "^4.41.2", "webpack-dev-server": "^3.10.1"},配置webpack: devServer: { contentBase: path.resolve(__dirname, 'dist'), hot: true, historyApiFallback: true, compress: true},hot为true,代表开启热更新contentBase表示告诉服务器从哪里提供内容。(也就是服务器启动的根目录,默认为当前执行目录,一般不需要设置)historyApiFallback使用HTML5历史记录API时,index.html很可能必须提供该页面来代替任何404响应compress对所有服务启用gzip压缩plugins: { HotModuleReplacementPlugin: new webpack.HotModuleReplacementPlugin()},配置热更新插件 module: { rules: [ { test: /\.(css|less)$/, use: [ process.env.NODE_ENV == 'development' ? { loader: 'style-loader' } : MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 1 } } ] } ]},style-loader库实现了HMR接口,当通过HMR收到更新时,它将用新样式替换旧样式。区分开发环境和生产环境,用不同loader。 src/index.jsx: if (module.hot) { module.hot.accept();}入口文件,新增上面代码,就可以了,非常简单。 ...

May 29, 2020 · 1 min · jiezi

图解Webpack实现Plugin

关注公众号“执鸢者”,回复“书籍”获取大量前端学习资料,回复“前端视频”获取大量前端教学视频。面试工作加分项!Plugin是webpack生态系统的重要组成部分,其目的是解决loader无法实现的其他事,可用于执行范围更广的任务,为webpack带来很大的灵活性。目前存在的plugin并不能完全满足所有的开发需求,所以定制化符合自己需求的plugin成为学习webpack的必经之路。下面将逐步阐述plugin开发中几个关键技术点并实现plugin。 一、Webpack构建流程在实现自己的Plugin之前,需要了解一下Webpack的构建流程(下图)。Webpack的构建流程类似于一条生产线(webpack的事件流机制),在特定时机会广播对应的事件,插件就可以监听这些事件的发生,从而在特定的时机做特定的事情。 上图中展示了Webpack构建流程的三个阶段及每个阶段广播出来的事件。初始化阶段:启动构建;紧接着从配置文件和Shell语句中读取并合并参数,得到最终参数;用上一步得到的参数初始化Compiler对象并加载所有配置的插件。从Entey出发,针对每个Module串行调用对应的Loader去翻译文件的内容,再找到该Module依赖的Module,递归地进行编译处理,得到每个模块被翻译后的最终内容及它们之间的依赖关系。根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk,再将每个Chunk转换成一个单独的文件加入到输出列表中,最终将所需输出文件的内容写入文件系统中。二、编写Plugin编写Plugin主要分为四个步骤: 创建一个具名JavaScript函数在其原型上定义apply方法给webpack构建流程中相关事件挂载事件钩子进行监听钩子函数触发后,利用compiler、compilation等进行相关操作,达到需要的效果2.1 基本结构class MyPlugin { constructor(options) { } apply(compiler) { console.log(compiler); compiler.hooks.emit.tap('MyPlugin', () => { console.log('plugin is used!!!'); }) }}module.exports = MyPlugin;2.2 apply方法apply 方法在安装插件时,会被 webpack compiler 调用一次。apply 方法可以接收一个 webpack compiler 对象的引用,从而可以在回调函数中访问到 compiler 对象。2.3 钩子函数在webpack整个编译过程中暴露出来大量的Hook供内部/外部插件使用,将Hook注册后即可实现对整个webpack事件流中对应事件的监听。这些钩子函数的核心是Tapable,该包暴露出很多钩子类,利用这些类创建了上述钩子函数。常见的钩子主要有以下几种: 暴露在compiler和compilation上的钩子函数均是基于上述钩子构建。 2.4 钩子函数注册方式 在plugin中,钩子注册方式有三种:tap、tapAsync、tapPromise,根据钩子函数的类型采用相应的方法进行注册。同步钩子函数利用tap注册,异步钩子函数利用tap、tapAsync、tapPromise进行注册。taptap可以用来注册同步钩子也能用来注册异步钩子。 compiler.hooks.compile.tap('MyPlugin', compilationParams => { console.log('以同步方式触及compile钩子')});tapAsynctapAsync能够用来注册异步钩子,并通过callback告知Webpack异步逻辑执行完毕。 compiler.hooks.run.tapAsync('MyPlugin', (compiler, callback) => { console.log('tapAsync 异步'); callback();});tapPromisetapPromise能够用来注册异步钩子,其通过返回Promise来告知Webpack异步逻辑执行完毕。(实现方式有两种,一种是通过返回Promse函数,另一种是利用async实现)。 // 方式一compiler.hooks.run.tapPromise('MyPlugin', (compiler) => { return new Promise(resolve => setTimeout(resolve, 1000)).then(() => { console.log('tapPromise 异步') })})// 方式二compiler.hooks.run.tapPromise('MyPlugin', async (compiler) => { await new Promise(resolve => setTimeout(resolve, 1000)); console.log('tapPromise 异步 async')})2.5 Compiler和CompilationCompiler和Compilation是Plugin和Webpack之间的桥梁,所以了解其具体含义至关重要,其含义如下:Compiler 对象包含了 Webpack 环境的所有配置信息,包含options、loaders、plugins等信息。这个对象在 Webpack 启动时被实例化,它是全局唯一的,可以简单地将它理解为 Webpack 实例。Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack以开发模式运行时,每当检测到一个文件发生变化,便有一次新的 Compilation 被创建。Compilation对象也提供了很多事件回调供插件进行扩展。通过 Compilation也能读取到 Compiler 对象。 ...

May 26, 2020 · 2 min · jiezi