就像绿色的初级自动重新加载器一样,他写了 hot 。 第2部分。CSS


前言


在对第一部分的评论中我正确地注意到术语的澄清。 因此,我现在将我的项目称为自动重载器(以下称为AR)。 对于历史,我将保留本文第一部分的标题。

前言


编写此最简单的重新加载器2周后,我就能够完全配置webpack和webpack-dev-server,从理论上讲,这将导致完全拒绝使用我的“自行车”。


设置新的程序集时,我尝试在“但您永远不知道什么”的情况下支持有保证的旧的工作程序集的可能性。
旧程序集的特征是项目中没有导入/需求,浏览器不支持该功能,并且在开发阶段,所有.js文件都包含在主体内部的index.html中。 这些是项目工作文件和所有库。

同时,正如我之前所说,所有库都位于整洁的lib爸爸中。
package.json文件在依赖项和devDependencies(以及脚本)方面几乎是纯净的。 仅表示一个服务器代理程序包,以及我添加的socket.io和node-watch。

因此,保留旧程序集的任务非常简单,但是相反,由于寻找必要的程序包及其版本,设置新程序集的任务变得复杂。
结果,实现了目标。 我用必要的软件包填充package.json,创建了entry.js和entry.html作为webpack输入文件。 在.js中,我将所有到达所有东西都导入最必要的东西,entry.html只是index.html的副本,在其中删除了所有用于连接文件的额外脚本。

可以肯定的是,在ProvidePlugin插件中,我描述了一个Webpack将在“按需”正确位置替换的库。 但现在我知道,您可以没有它。 我将尝试删除,让我们看看会发生什么。
因此,他支持主要项目中没有进口商品,并保留了原始index.htm。

从理论上讲,这应该允许我与旧的收集器进行收集,并且-对我个人而言这很重要-使用我的自动重新加载器支持开发。
在实践中,我发现了出现出口的地方。 我们自己编写的微型图书馆之一是以物体的形式制成的。

为了使webpack程序集正常运行,需要将其导出;对于普通的旧程序集,只需index.html中的脚本就足够了。 好吧,什么都没有,我接受并用角度服务重写了它。 复制+过去+小更改-瞧-可行!

我尝试了一个新的程序集-它也可以工作,分别是webpack-dev-server。
我尝试使用我的自动重新加载器-可以运行!
嗡嗡声!
序言结束,继续。

剧情。


在webpack-dev-server上工作了几天后,我只是想不起来要多长时间。
而且他的速度非常快,保存后大约3-4秒会重新启动。
但是我已经习惯了我的AR,因为缺少程序集,它会在ctrl + s之后立即重新启动。
结果,起初我使两个工具都运行,然后仅通过AR工作。

我自己确定了以下4个原因:
1. AR更快。
2.与他比较清楚发生了什么事,因为 源文件中的整个错误堆栈都是可见的。 不需要wds捆绑包浏览。
3.当我更改通过包含在另一个html文件中的html文件中的内容时,Wds不会重新启动。 我的-由于它读取整个项目文件夹并在发生任何更改(例外除外)后重新加载,因此重新加载。 在这里,wds优化可谓一发不可收拾。
4.好吧,主观的。 我需要经常查看来自不同服务器的后台,并相应地在浏览器中的不同端口上运行它。 1个脚本足以为AR服务
“example”: “node ./server.js”

哪个运行
npm run example 1.100 9001


npm run example 1.101 9002

其中1.101服务器和9001端口显示在我的本地主机上。
通常,使用起来很方便,您无需记住脚本的不同名称,而只需在脚本开始处编写参数即可。
变量进入process.argv,我在server.js中成功地将它们带出了自己

至于wds,到目前为止,我还无法实现这种便利,我不得不为主要组合编写几个脚本。 那么至少有一个配置用于开发。

总的来说,我骑自行车更方便。
好吧,因为它更方便,所以我决定开发该项目。

有哪些选择?
1.更改css文件时,请勿重新加载页面,但请滚动更改。
2.同样,但已经是.html
3.尝试使用js的location.reload()以外的其他选项。
4.与1-2类似,但已经是.js
5.将index.html + entry.html移到两个程序集的一个文件中。 即 出现一种情况,即将要进行webpack打包的东西将在我的AR上运行。
6,加强对scss的支持

CSS很酷,您需要什么。
HTML也很有趣,正是您所需要的。
Location.reload()。 我不知道为什么它不好,但是考虑各种可用选项将很有趣。
JS-很酷,这样做很酷,但是考虑到我要花多少精力,真的有必要吗?
5和6-这已经有点组装问题,这意味着速度可能会消失。
结论:第4-6项没有计划,我将做第1-2项,第3项将介绍总体情况。 乍看之下,任务很艰巨,但我可以分解为子任务! 我将其分解并决定分阶段进行,而我只考虑当前阶段(是的,很好!我已经考虑过使用may和main编写html了)

主要部分。


的CSS


该任务包含两个子任务:
1.找到修改后的文件。
2.重新加载CSS,而不重新加载页面。

我从第二个开始。 使用以前的经验,我首先要去google,但是通常如何在不重新加载页面的情况下重新加载css。

我碰到了很多文章,其中我觉得这是最有趣的

伙计们只是绕过了从CSS到head的所有链接,并将href属性更改为一个新链接。
我以他们的想法为基础并实施了我的版本。
我还有2个档案。
server.js是一个简单的服务器+异常检查+更改跟踪逻辑+通过套接字发送更改。

watch.js-在客户端上。 从服务器接收更改消息+ location.reload()。 现在,在watch.js中添加了检查css上的名称并在必要时替换css的逻辑。 可以在单独的模块中将其取出,但是到目前为止,我看不到太多代码。 第一次迭代结果如下:

server.js
 const express = require('express'), http = require('http'), watch = require('node-watch'), proxy = require('http-proxy-middleware'), app = express(), server = http.createServer(app), io = require('socket.io').listen(server), exeptions = ['git', 'js_babeled', 'node_modules', 'build', 'hotreload'], // ,   ,    backPortObj = { /*  ,   back*/ }, address = process.argv[2] || /*    back*/, localHostPort = process.argv[3] || 9080, backMachinePort = backPortObj[address] || /*   back */, isHotReload = process.argv[4] || "y", // "n" || "y" target = `http://192.168.${address}:${backMachinePort}`, str = `Connected to machine: ${target}, hot reload: ${isHotReload === 'y' ? 'enabled' : 'disabled'}.`, link = `http://localhost:${localHostPort}/`; server.listen(localHostPort); app .use('/bg-portal', proxy({ target, changeOrigin: true, ws: true })) .use(express.static('.')); if (isHotReload === 'y') { watch('./', { recursive: true }, (evt, name) => { let include = false; exeptions.forEach(item => { if (`${name}`.includes(item)) include = true; }) if (!include) { console.log(name); io.emit('change', { evt, name, exeptions }); }; }); }; console.log(str); console.log(link); 



watch.js
 const socket = io.connect(); const makeCorrectName = name => name.replace('\\','\/'); const findCss = (replaced) => { const head = document.getElementsByTagName('head')[0]; const cssLink = [...head.getElementsByTagName('link')] .filter(link => { const href = link.getAttribute('href'); if(href === replaced) return link; }) return cssLink[0]; }; const replaceHref = (cssLink, replaced) => { cssLink.setAttribute('href', replaced); return true; }; const tryReloadCss = (name) => { const replaced = makeCorrectName(name); const cssLink = findCss(replaced); return cssLink ? replaceHref(cssLink, replaced) : false; }; socket.on('change', ({ evt, name, exeptions }) => { const isCss = tryReloadCss(name); if (!isCss) location.reload(); }); 



有趣的是,node-watch包以路径\到\ file.css的形式向我发送了修改后的文件的名称,而在href中,该路径是将路径/写入了/ file.css。 因为 我按文件全名检查文件;我不得不将斜杠更改为反斜杠以进行检查。
而且有效!

但是,仍然存在3个问题。
1.Option适用于镀铬,绝对不适用于边缘。 在这里你必须挖,因为 但是,多浏览器设计是非常必要的(正是布局方面的改进),但这可能是由于两个问题。

2.浏览器很聪明:它缓存已加载的文件,并且如果不更改参数,则不会更改任何内容。 也就是说,从理论上讲,如果使用相同的名称保存文件,则浏览器将认为没有任何变化,并且不会重新加载内容。 为了解决这个问题,这些家伙每次都改名。 没有这个,它对我来说就适用于chrome,但是,这太重要了。

3.名称的明确重合是必要的。 即 如果您设置链接的绝对路径(以./开头),则程序找不到匹配项。
./path/to/file!=了解路径/到/文件,了解我的代码的逻辑。 这也需要解决。

因此,我需要每次都更新文件名,以便没有缓存。
更准确地说,每次更改链接的href属性时,css文件都已更改。
在此处了解更多信息

上面链接中的人非常努力地进行缓存,我选择了:
 cssLink.setAttribute('href', `${hrefToReplace}?${new Date().getTime()}`); 

接下来,我需要比较文件名。 我每行有1个问号,因此我可以不用正则表达式(还没有研究过它们)来支持这种自写方法:
 const makeCorrectName = (name) => name .replace('\\', '/') .split('?')[0]; 


有效!

接下来,我需要唯一地确定文件的路径。
我不太了解绝对路径,相对路径和一般路径的魔力。 正因为如此,对这个问题有些误解。
href的路径可以以“。”,“ /”开头或以名称开头。
在空闲时间,我考虑了这个问题。
入口点-index.html(在我的情况下为entry.html)-始终(通常)位于顶层。 通过脚本连接的css文件通常(通常)位于深处。 因此-我再说一遍-路径将始终相同(文件夹和文件名),只有第一个字符会不同。
因此,在用问号分隔部分之后,我以相同的方式再次打断了行,但已经在'/'中,然后删除了预期的第一点并将数组元素连接到一行中,根据该行我将进行比较以进行精确搜索。
看起来像这样:
 const findFullPathString = (path) => path .split('/') .filter((item) => item !== '.') .filter((item) => item) .join(''); 


我运行代码,干杯,行得通!

边缘呢?


而使用Edge,问题并没有隐藏在搜索位置。
事实证明,我的CSS代码在Edge中不起作用,由于我的粗心,我只是没有注意到这一点。
该问题隐藏在处理DOM元素集合的方法中。
如您所知,DOM元素的集合不是数组;因此,数组方法无法使用它(更确切地说,有些工作无法实现)。
我曾经这样做:
 const cssLink = [...head.getElementsByTagName('link')] 

但是,好的旧Edge无法理解这一点,这就是原因。
随时进行更改,现在可以这样进行:
 const cssLink = Array.from(head.getElementsByTagName('link'))// special for IE 

运行,检查,工作!
图片
图片很小,有点解释。
左Chrome,中置Firefox,右Edge。 我在输入中专门输入了一个值,以显示该页面不会重新加载,并且CSS几乎立即更改。
视频中的延迟与编辑和保存文件之间的延迟有关。

就CSS而言,使用chromeDevTools可以更快,因为它们可以例如使用向上/向下箭头更改边距,但是我的CSS也可以从一个编辑器快速更新。
值得注意的是,在文章发表之时,我一直在不停修改的情况下持续使用我的自行车大约2周,并且不希望改用wds。 由于在简单的情况下没有使用CSS的欲望,因此不要使用devTools!

总计,server.js保持不变,而watch.js采用以下形式:
watch.js
 const socket = io.connect(); const findFullPathString = (path) => path .split('/') .filter((item) => item !== '.') .filter((item) => item) .join(''); const makeCorrectName = (name) => name .replace('\\', '/') .split('?')[0]; const findCss = (hrefToReplace) => { const head = document.getElementsByTagName('head')[0]; const replacedString = findFullPathString(hrefToReplace); const cssLink = Array.from(head.getElementsByTagName('link'))// special for IE .filter((link) => { const href = link.getAttribute('href').split('?')[0]; const hrefString = findFullPathString(href); if (hrefString === replacedString) return link; }); return cssLink[0]; }; const replaceHref = (cssLink, hrefToReplace) => { cssLink.setAttribute('href', `${hrefToReplace}?${new Date().getTime()}`); return true; }; const tryReloadCss = (name) => { const hrefToReplace = makeCorrectName(name); const cssLink = findCss(hrefToReplace); return cssLink ? replaceHref(cssLink, hrefToReplace) : false; }; socket.on('change', ({ name }) => { const isCss = tryReloadCss(name); if (!isCss) location.reload(); }); 



美女!

后记。


下一步,我想尝试重新加载HTML,但是到目前为止,我的愿景看起来非常复杂。 需要说明的是,我有angularjs,它应该一起工作。
对于建设性的批评以及您对如何改进我的小型项目的评论以及有关HTML主题的提示和文章,我将感到非常高兴。

Source: https://habr.com/ru/post/zh-CN467771/


All Articles