你的网站或许不需要前端构建

news/2024/5/15 18:35:56/文章来源:https://blog.csdn.net/soulteary/article/details/90587584

本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2019年05月27日
统计字数: 8760字
阅读时间: 18分钟阅读
本文链接: https://soulteary.com/2019/05/27/your-website-may-not-need-front-end-builds.html


你的网站或许不需要前端构建

自从几年前 Webpack 替换掉了 GulpGrunt 后,我们可以明显看到前端项目的工程复杂度越来越高,前端技术迭代速度也越来越快。

大厂也好、培训班也罢,都针对 Webpack、Babel 、ESLint 前端工程工具三巨头贡献出了数不胜数分享和案例。

但是随之而来的是,前端项目几乎没有了往日的“简单愉快”,想用流行框架写一个项目,一般得先整一个脚手架,如果你写的程序没有“经历前端构建”,整的你都不好意思和同行打招呼。

这篇文章会以两个简单的例子来说明,即使不配置脚手架、使用一些“老家伙”一样可以开发出高性能的网站。

额外说明

本篇文章并不完全适用十几人乃至几十人以上团队规模的复杂、需要高密度的协作项目,仅针对中小型项目,诸如简单的后台、流程配置、甚至是 Demo。

碎碎念了这么多,让我们正式开始回归愉快的前端开发

从一个简单的“单页”应用开始

不论是使用 ReactVue 还是使用更有年代感的 jQuery ,做一个简单的页面,不外乎分别完成 “页面结构”、“页面风格”、“页面功能” 三个部分的编写。

我们使用现在比较流行的 Vue 举个例子:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>简单的页面</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ant-design-vue@1.3.8/dist/antd.min.css"><!-- 你也可以选择保存在本地使用, 脚本资源也是一样 --><!-- <link rel="stylesheet" href="assets/common/antd-v1.3.8.min.css"> --><style>body{color:#2c3e50}#header{height:50px;background:#fff;border-bottom:1px solid #eceef1}#header-nav{float:left;height:50px}#header-search{float:right;width:180px;margin:4px}#header-button{float:right;height:50px;overflow:hidden;line-height:50px}#has-team-news{top:-7px;left:-3px}.logo{width:120px;height:100%;line-height:50px;font-weight:bold;background:rgba(255,255,255,.2);float:left}#left-menu{margin-top:10px}#left-menu-wrap{padding-left:10px;margin-left:10px}#top-switch{margin-top:10px;overflow:hidden}#top-switch-2{float:right;overflow:hidden;width:100px;height:20px;line-height:20px;margin-top:10px}#top-switch-2 a{font-size:12px}#top-switch-2 a.grey{color:gray}#top-divider{margin:10px}#post-container{margin:10px}.slick-slide{text-align:center;height:160px;line-height:160px;background:#364d79;overflow:hidden}.slick-slide h3{color:#fff}#carousel{margin:10px}.demo-loadmore-list{min-height:350px}.post-meta{display:inline-block;font-size:13px;line-height:13px;height:13px;overflow:hidden;font-style:italic;margin-right:4px}.desc{margin:14px 0;font-size:16px}#tag-list .ant-tag{margin-bottom:8px}.item-people{margin:10px 0}#ranking .ant-tabs-top-bar{margin-bottom:0}#car-list,#cars-list{border-top:none}</style><script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script><script src="https://cdn.jsdelivr.net/npm/ant-design-vue@1.3.8/dist/antd.min.js"></script>
</head>
<body><div id="app"><a-layout><a-layout-header id="header"><div class="logo">博客Logo摆放</div><a-menu mode="horizontal" :defaultSelectedKeys="['1']" id="header-nav"><a-menu-item key="1">首页</a-menu-item><a-menu-item key="2">团队<a-badge id="has-team-news" status="success"></a-badge></a-menu-item><a-menu-item key="3">标签</a-menu-item></a-menu><a-button-group id="header-button"><a-button icon="file-text"></a-button><a-button icon="star"></a-button><a-button icon="user"></a-button></a-button-group><a-input-search id="header-search" placeholder="你不知道啥?问我鸭" /></a-layout-header><a-layout-content><a-row type="flex"><a-col :span="4"><div id="left-menu-wrap"><a-menu id="left-menu" mode="inline" :openKeys="openKeys" @openChange="onMenuOpenChange"><a-sub-menu key="sub0"><span slot="title"><a-icon type="home"></a-icon><span>推荐</span></span><a-menu-item key="1">牛逼的比赛</a-menu-item><a-menu-item key="2">犀利的观点</a-menu-item><a-menu-item key="3">给力的事件</a-menu-item><a-menu-item key="4">特别的曝光</a-menu-item></a-sub-menu><a-sub-menu key="sub1"><span slot="title"><a-icon type="html5"></a-icon><span>前端</span></span><a-menu-item key="1">最佳实践</a-menu-item><a-menu-item key="2">基础知识</a-menu-item><a-menu-item key="3">多彩样式</a-menu-item><a-menu-item key="4">有趣脚本</a-menu-item></a-sub-menu><a-sub-menu key="sub2"><span slot="title"><a-icon type="codepen"></a-icon><span>后端</span></span><a-menu-item key="5">Option 5</a-menu-item><a-menu-item key="6">Option 6</a-menu-item><a-sub-menu key="sub3" title="Submenu"><a-menu-item key="7">Option 7</a-menu-item><a-menu-item key="8">Option 8</a-menu-item></a-sub-menu></a-sub-menu><a-sub-menu key="sub3"><span slot="title"><a-icon type="appstore"></a-icon><span>运维</span></span><a-menu-item key="9">Option 9</a-menu-item><a-menu-item key="10">Option 10</a-menu-item><a-menu-item key="11">Option 11</a-menu-item><a-menu-item key="12">Option 12</a-menu-item></a-sub-menu><a-sub-menu key="sub4"><span slot="title"><a-icon type="html5"></a-icon><span>算法</span></span><a-menu-item key="9">Option 9</a-menu-item><a-menu-item key="10">Option 10</a-menu-item><a-menu-item key="11">Option 11</a-menu-item><a-menu-item key="12">Option 12</a-menu-item></a-sub-menu><a-sub-menu key="sub5"><span slot="title"><a-icon type="html5"></a-icon><span>分类</span></span><a-menu-item key="9">Option 9</a-menu-item><a-menu-item key="10">Option 10</a-menu-item><a-menu-item key="11">Option 11</a-menu-item><a-menu-item key="12">Option 12</a-menu-item></a-sub-menu><a-sub-menu key="sub6"><span slot="title"><a-icon type="html5"></a-icon><span>分类</span></span><a-menu-item key="9">Option 9</a-menu-item><a-menu-item key="10">Option 10</a-menu-item><a-menu-item key="11">Option 11</a-menu-item><a-menu-item key="12">Option 12</a-menu-item></a-sub-menu></a-menu></div></a-col><a-col :span="14"><a-carousel id="carousel" autoplay><div><h3>凉风有幸 1</h3></div><div><h3>秋月无边 2</h3></div><div><h3>啦啦啦啦 3</h3></div><div><h3>置顶精选 4</h3></div></a-carousel><div id="top-switch"><a-dropdown><a-menu slot="overlay" @click="handleTopMenuClick"><a-menu-item key="1"><a-icon type="user"></a-icon>编辑精选</a-menu-item><a-menu-item key="2"><a-icon type="user"></a-icon>最新发布</a-menu-item></a-menu><a-button style="margin-left: 8px">编辑精选<a-icon type="down" /></a-button></a-dropdown><div id="top-switch-2"><a href="#">热门</a><a-divider type="vertical"></a-divider><a href="#" class="grey">最新</a></div><a-divider id="top-divider"></a-divider></div><div id="post-container"><a-list class="demo-loadmore-list" :pagination="pagination" :loading="loading"itemLayout="horizontal" :dataSource="postDataSource" :locale="{emptyText: '暂无数据'}"><div v-if="showLoadingMore" slot="loadMore":style="{ textAlign: 'center', marginTop: '12px', height: '32px', lineHeight: '32px' }"><a-spin v-if="loadingMore" /><a-button v-else @click="onLoadMore">loading more</a-button></div><a-list-item v-for="(item, index) in postDataSource"><a-card style="width:100%"><h2>这是一篇博客的标题,可能很长很长很长很长</h2><div class="post-meta"><a-icon type="user"></a-icon>@nickname</div><div class="post-meta"><a-icon type="clock-circle"></a-icon>10分钟前</div></a-avatar><p class="desc">简单的内容描述。</p><div style="float:left"><a-tag>前端</a-tag><a-tag>工程工具</a-tag><a-tag>方法论</a-tag></div><div class="post-meta" style="float:right"><span><a-icon type="like" style="margin-right: 8px"></a-icon></span><span><a-icon type="star" style="margin-right: 8px"></a-icon></span><span><a-icon type="message" style="margin-right: 8px"></a-icon></span></div></a-card></a-list-item></a-list><a-pagination :defaultCurrent="6" :total="500" /></div></a-col><a-col :span="6"><a-card style="margin: 10px; border-color: #42b983;"><h3 style="color:#42b983"><a-icon type="notification" style="margin-right: 8px"></a-icon>这里是一个公告标题</h3><p>这里有一个描述性词汇描述性词汇描述性词汇描述性词汇描述性词汇</p><a-button style="width:100%;background:#42b983;border-color: #42b983;color: #fff;">开始浏览</a-button></a-card><a-card id="tag-list" style="margin: 10px;"><h3><a-icon type="tag" style="margin-right: 8px"></a-icon>热门标签</h3><a-divider></a-divider><a-tag>前端</a-tag><a-tag>工程工具</a-tag><a-tag>方法论</a-tag><a-tag>工程工具</a-tag><a-tag>方法论</a-tag><a-tag>前端</a-tag><a-tag>方法论</a-tag><a-tag>工程工具</a-tag><a-tag>方法论</a-tag><a-tag>前端</a-tag></a-card><a-tabs defaultActiveKey="2" style="margin: 10px;" type="card" id="ranking"><a-tab-pane tab="月度优秀作者" key="1"><a-card id="car-list"><div class="item-people"><a-avatar style="margin-right:4px">1</a-avatar><a href="#">作者 - 简单描述</a><a-badge style="zoom:0.8" count="12":numberStyle="{backgroundColor: '#8bc34a'} " /></div><div class="item-people"><a-avatar style="margin-right:4px">2</a-avatar><a href="#">作者 - 简单描述</a><a-badge style="zoom:0.8" count="10":numberStyle="{backgroundColor: '#8bc34a'} " /></div><div class="item-people"><a-avatar style="margin-right:4px">1</a-avatar><a href="#">作者 - 简单描述</a><a-badge style="zoom:0.8" count="9":numberStyle="{backgroundColor: '#8bc34a'} " /></div><div class="item-people"><a-avatar style="margin-right:4px">4</a-avatar><a href="#">作者 - 简单描述</a><a-badge style="zoom:0.8" count="7":numberStyle="{backgroundColor: '#8bc34a'} " /></div><div class="item-people"><a-avatar style="margin-right:4px">5</a-avatar><a href="#">作者 - 简单描述</a><a-badge style="zoom:0.8" count="6":numberStyle="{backgroundColor: '#8bc34a'} " /></div><div class="item-people"><a-avatar style="margin-right:4px">6</a-avatar><a href="#">作者 - 简单描述</a><a-badge style="zoom:0.8" count="2":numberStyle="{backgroundColor: '#8bc34a'} " /></div></a-card></a-tab-pane><a-tab-pane tab="月度优秀作者" key="2"><a-card id="cars-list"><div class="item-people"><a-avatar style="margin-right:4px">1</a-avatar><a href="#">作者</a><a-badge style="zoom:0.8" count="109":numberStyle="{backgroundColor: '#8bc34a'} " /></div><div class="item-people"><a-avatar style="margin-right:4px">1</a-avatar><a href="#">作者</a><a-badge style="zoom:0.8" count="109":numberStyle="{backgroundColor: '#8bc34a'} " /></div><div class="item-people"><a-avatar style="margin-right:4px">1</a-avatar><a href="#">作者</a><a-badge style="zoom:0.8" count="109":numberStyle="{backgroundColor: '#8bc34a'} " /></div></a-card></a-tab-pane></a-tabs></a-col></a-row></a-layout-content><a-layout-footer><div><a-divider>-EOF-</a-divider><a-divider type="vertical"></a-divider><a href="#">投稿</a><a-divider type="vertical"></a-divider><a href="#">关于</a></div></a-layout-footer></a-layout></div><script>
Vue.use(antd);const posts = [[],[],[],[],[],[],]var app = new Vue({el: '#app',data() {return {rootSubmenuKeys: ['sub0', 'sub1', 'sub2', 'sub3', 'sub4', 'sub5', 'sub6'],openKeys: ['sub0'],loading: true,loadingMore: false,showLoadingMore: true,postDataSource: posts,pagination: {onChange: (page) => {console.log('Change Page', page);},pageSize: 3,},}},mounted() {this.getData((res) => {this.loading = falsethis.postDataSource = res})},methods: {onMenuOpenChange(openKeys) {const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {this.openKeys = openKeys} else {this.openKeys = latestOpenKey ? [latestOpenKey] : []}},handleButtonClick(e) {console.log('Button Clicked', e);},handleTopMenuClick(e) {console.log('Top Menu Clicked', e);},getData(callback) {setTimeout(() => {callback(posts)}, 300)},onLoadMore() {this.loadingMore = truethis.getData((res) => {this.postDataSource = this.postDataSource.concat(res)this.loadingMore = falsethis.$nextTick(() => {window.dispatchEvent(new Event('resize'))})})},},
})
</script></body>
</html>

将上面的三百来行代码保存为 index.html, 使用浏览器直接打开,不出意外你将看到下面的界面。

一个简单的单页 Demo

简单把玩之后,你一定会说,这个示例页面没有什么复杂交互,而且这不就是官方的推荐用法之一嘛。

是的,但希望你能够看到,像上面这样做一个样子还说的过去的页面,真的不是必须把构建工具也“掺和”进来,即使你把组件交互的部分填充完毕。

而开发过程,就可以回归经典的“边改边刷新”,所见即所得了。

接下来,我们来聊聊如何将上面的程序拆分为模块使用,让多个页面之间可以复用模块,当然还是在不使用构建工具的前提下。

拆分功能模块

将单一职责的功能抽象模块化,可以说是工程师们的日常。这样做除了提高了可维护性、潜在的提升了页面性能、让软件构建更灵活之外、最大的收益便是增加了功能模块的可复用性。

我们日常使用 webpack 的时候,一定有看到过被分割为一堆名为 chunk 文件的脚本,或者名称可能叫做 vendorappcomponent 的文件。这些便是构建程序帮我们切割的软件模块了,甚至是上面例子中引入的 *.min.js. 也是如此。

如果我们不使用构建工具进行模块拆分,该怎么做呢?这里面常见的坑有哪些呢?

  1. 拆分为多个模块之后,会涉及到额外的网络资源获取和解析处理。
  2. 拆分为多个模块之后,可能会涉及到额外的模块依赖管理。
  3. 拆分为多个模块之后,会涉及到数据、状态同步管理。

想要解决前两个问题,可以通过使用 Require.js 之类的资源加载器,来控制拆分后多出来的资源文件的加载和对模块进行依赖管理,想了解这个老家伙的细节,可以浏览它的官方网站。

而拆分后的模块,想要保持书写上的简单明快,这里选择使用 Vue 的 Component 语法进行模块保存,所以需要额外引入一个模块解析器,原理很简单,通过 XHR 方法将资源获取后,使用正则将内容分别抽取为“样式”、“脚本”、“模版”,然后在合适的时机在浏览器环境执行。为了简化操作,我在 requirejs-vue 的基础上进行了删减,有兴趣可以围观源码。

至于第三个问题,不论是使用单例共享数据源、亦或者使用发布订阅模式传递数据、或者使用观察者模式都可以,解决的手段还有很多,就不扩展了,本文暂且略过,你可以挑一个你觉得顺手的使用。

以上面的单页程序为例,我们先编写页面框架。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>将模版分离</title><link rel="stylesheet" href="assets/common/antd-v1.3.8.min.css"><script src="assets/common/vue-v2.6.10.min.js"></script><script src="assets/common/moment-v2.24.0.min.js"></script><script src="assets/common/antd-v1.3.8.min.js"></script><script src="assets/common/require-v2.3.6.min.js"></script><script>Vue.use(antd);requirejs && requirejs.config({baseUrl: './assets',paths: { 'vue': 'common/require-vue' },config: { 'vue': { 'css': 'inject', 'templateVar': '__template__' } }});</script>
</head>
<body><div id="app"><a-layout><a-layout-header id="header"></a-layout-header><a-layout-content><a-row type="flex"><a-col id="navbar" :span="4"></a-col><a-col id="main" :span="14"></a-col><a-col id="sidebar" :span="6"></a-col></a-row></a-layout-content><a-layout-footer id="footer"></a-layout-footer></a-layout></div><script>requirejs(['vue!template/header.html','vue!template/footer.html','vue!template/navbar.html','vue!template/sidebar.html','vue!template/carousel.html','vue!template/feed.html',], function (header, footer, navbar, sidebar, carousel, feed) {var appInst = new Vue({ el: '#app' });var headerInst = new Vue({ el: '#header' });header.$mount();headerInst.$el.appendChild(header.$el);var footerInst = new Vue({ el: '#footer' });footer.$mount();footerInst.$el.appendChild(footer.$el);var navbarInst = new Vue({ el: '#navbar' });navbar.$mount();navbarInst.$el.appendChild(navbar.$el);var sidebarInst = new Vue({ el: '#sidebar' });sidebar.$mount();sidebarInst.$el.appendChild(sidebar.$el);var mainInst = new Vue({ el: '#main' });carousel.$mount();mainInst.$el.appendChild(carousel.$el);feed.$mount();mainInst.$el.appendChild(feed.$el);});</script>
</body>
</html>

相比较上一小节三百来行混杂了细节逻辑的代码,这个长度只有不到一百行的代码是不是逻辑清晰许多呢。

刚刚提到了模块复用,其实也很简单,比如我们想实现一个“列表页面”,可以这么写:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>复用模块的例子</title><link rel="stylesheet" href="assets/common/antd-v1.3.8.min.css"><script src="assets/common/vue-v2.6.10.min.js"></script><script src="assets/common/moment-v2.24.0.min.js"></script><script src="assets/common/antd-v1.3.8.min.js"></script><script src="assets/common/require-v2.3.6.min.js"></script><script>Vue.use(antd);requirejs && requirejs.config({baseUrl: './assets',paths: { 'vue': 'common/require-vue' },config: { 'vue': { 'css': 'inject', 'templateVar': '__template__' } }});</script>
</head>
<body><div id="app"><a-layout><a-layout-header id="header"></a-layout-header><a-layout-content><a-row type="flex"><a-col :pull="5" :push="5" :span="14" id="main"></a-col></a-row></a-layout-content><a-layout-footer id="footer"></a-layout-footer></a-layout></div><script>requirejs(['vue!template/header.html','vue!template/footer.html','vue!template/list.html',], function (header, footer, submit) {var appInst = new Vue({ el: '#app' });var headerInst = new Vue({ el: '#header' });header.$mount();headerInst.$el.appendChild(header.$el);var footerInst = new Vue({ el: '#footer' });footer.$mount();footerInst.$el.appendChild(footer.$el);var mainInst = new Vue({ el: '#main' });submit.$mount();mainInst.$el.appendChild(submit.$el);});</script>
</body>
</html>

聊完页面框架后,我们接着来看看拆分出的模块怎么写,以一个简单的 header 模块举例:

<script>
define([], function() {return new Vue({template: __template__,data() {return {}},mounted() {},methods: {},})
});
</script><style>
#header{height:50px;background:#fff;border-bottom:1px solid #eceef1}#header-nav{float:left;height:50px}#header-search{float:right;width:180px;margin:4px}#header-button{float:right;height:50px;overflow:hidden;line-height:50px}#has-team-news{top:-7px;left:-3px}.logo{width:120px;height:100%;line-height:50px;font-weight:bold;background:rgba(255, 255, 255, .2);float:left}
</style><template><div><div class="logo">博客Logo摆放</div><a-menu mode="horizontal" :defaultSelectedKeys="['1']" id="header-nav"><a-menu-item key="1">首页</a-menu-item><a-menu-item key="2">团队<a-badge id="has-team-news" status="success"></a-badge></a-menu-item><a-menu-item key="3">标签</a-menu-item></a-menu><a-button-group id="header-button"><a-button icon="file-text"></a-button><a-button icon="star"></a-button><a-button icon="user"></a-button></a-button-group><a-input-search id="header-search" placeholder="你不知道啥?问我鸭"></a-input-search></div>
</template>

可以看到,这完全就是普通的 Vue 组件模版嘛。

其他模块的代码可以在这里找到,拆分方式大同小异,在此就不进行赘述。

和上一小节不同的是,因为我们使用了 XHR 的方式获取资源,所以使用浏览器直接打开 HTML 页面的方法来预览效果,会得到类似下面的报错而无法得到想要的结果。

Access to XMLHttpRequest at 'file:///Users/soulteary/You-Dont-Need-Webpack/src/assets/template/header.html' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https. 

这里解决的方法很简单,将页面扔到一个能够提供 HTTP 服务的程序里就好了,可以使用 Node(HTTP Server、Express、KOA)等方案、也可以使用 Apache、Nginx、Caddy… 选择你顺手的工具就好啦。

在 GitHub 仓库中,我提供了一个 docker-compose.yml 编排文件,如果你本地有安装 Docker 的话,只需要 Clone 下来项目,接着执行 docker-compose up ,打开 localhost:10240/split.html 就能看到预览结果了。

[外链图片转存失败(img-qifPXxA2-1563359483046)(https://soulteary-1252604058.cos.ap-beijing.myqcloud.com/2019/05/27/split-view.png)]

体验增强

如果你想获取和 Webpack 实时刷新页面的开发体验,可以考虑全局安装 browsersync 这个工具,除了根据文件是否修改来刷新页面之外,这个老家伙还能同步不同设备上,当前调试页面的滚动、点击事件等交互操作。介绍这个工具的具体细节,不在本文范畴,有兴趣的小伙伴可以访问它的官方网站: https://www.browsersync.io/ 。

在本例中,我们将模块拆分为多个 .html 文件,虽然请求数多了,无法像传统脚本、样式资源一样享受服务端 combo 的能力。

但是因为使用了 HTML、又没有经过构建压缩混淆,配合 CMS 实时更新一些配置,改变页面功能反而变得更容易进行操作了。毕竟上线后毋需构建发版。(可以了解淘宝 TMS 模块化方案)

看起来变多的请求

另外,如果实在对请求数敏感,可以针对模块加载器进行优化,实现类似 lsloader 之类的本地强缓存+资源版本管理的功能,减少请求获取。不过已经 2019 年,这点请求数对于多路复用的 HTTP2,随处可见的大带宽完全不是问题。

即使不使用 HTTPS(HTTP2)的方式打开页面,进行模块化拆分的页面首屏体验也优于未拆分页面。

未拆分模块的页面

未进行模块化拆分的页面刷新后,会明显出现页面白屏抖动。

进行了模块拆分的页面

而拆分模块的页面,展示则会“顺滑”许多,当然如果你追求极致,还可以添加骨架屏。

如果上面的动图还不够清楚的话,可以看两种情况下的性能测试。

[外链图片转存失败(img-sAqdKeQQ-1563359483048)(https://soulteary-1252604058.cos.ap-beijing.myqcloud.com/2019/05/27/single-profile.png)]

未拆分页面首帧虽然快,但是随着业务脚本的复杂,Evaluate Script 的时间也会越来越长,导致 DOM Content Loaded 被无限滞后,在用户体验上会带来卡顿感。

进行了模块拆分的页面

而进行拆分了页面模块拆分后,DOM Content Loaded 时机被极大的提前,虽说整体脚本复杂度不变,但是单一模块复杂度变低,伴随 DCL 时间提前,模块脚本的解析完毕时间也提前了。

最后

再次重申,本篇文章不是说我们开发项目不进行脚手架配置、完全不使用 Webpack 等前端优秀工具。

重点是在拥有搭建开发环境的能力后,在适合的场景下,我们应该适当灵活变通,使用更简单轻快的方案进行开发,腾出配置环境、安装模块的时间去做更有意思的事情。

本文示例中的界面,参考了 https://love2.io/掘金 的设计,感谢设计师们的辛苦付出。

—EOF

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_814346.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

独立官网建设SEO优化指南,刚学搭建卖家商城网页也能获取免费流量

独立官网建设SEO优化指南&#xff0c;新手搭建卖家商城网页也能获取免费流量&#xff01; 大家好&#xff0c;欢迎观看USB自建站平台跨境电商讲堂&#xff0c;今天这期视频主要内容就是来分享独立这样的CEO优化指南&#xff0c;可能很多卖家会觉得店铺或者网站已经做了Faceboo…

织梦程序的网站文章可以一键迁移到人人站吗?

织梦程序的网站文章可以一键迁移到人人站吗&#xff1f; 织梦转人人站 - 模板数据无缝对接&#xff08;增强版&#xff09; 一键将织梦内容转移到人人站&#xff0c;一键转移织梦模版到人人站。 安装使用和原转移插件一致&#xff0c;详情查看&#xff1a; 任意安装一套人人…

SEO优化论坛让我懂了没团队经验,看如何制作短视频赚钱一天20元

SEO优化论坛让我懂了没团队经验&#xff0c;看如何制作短视频赚钱一天20元 都知道短视频博主特赚钱。 可是咱们自己一没经验。 二没团队。 连做什么内容都没人告诉我。 也想过找人知道&#xff0c;但是肯定得花钱&#xff0c;花钱倒是不怕&#xff0c;关键是没效果怎么办&…

独立站建设 新网站几个页面上线比较好?

独立站建设 新网站几个页面上线比较好&#xff1f; 昨天直播的时候有朋友问网站上线的时候应该是多少个页面&#xff0c;可能效果比较好。 如果你的网站是10个网页刚上线了&#xff0c;你觉得谷歌会对你的 网站有多少信任值呢&#xff1f; 就是当我们一个网站上线之前&#xff…

网站超链接同步百家号软件

网站超链接同步百家号软件 竞价广告的转化率是竞价专员以及公司最关注的重要数据之一&#xff0c;我已经做了很长时间的竞价了&#xff0c; 但是竞价的转化率很低&#xff0c;效果很差&#xff0c;那么怎么去提高这一个转化率呢&#xff1f; 其实针对不同的行业&#xff0c;不…

网站锚文本链接同步百家号

网站锚文本链接同步百家号 有流量就一定能赚到钱吗&#xff1f;答案是否定的&#xff0c;有人去超市逛了&#xff0c;但是却没有购物&#xff0c;这种可能是有的&#xff0c;这就是有流量没销量&#xff0c;不赚钱不赚钱的原因有两点&#xff0c; 一流量质量差&#xff0c;客户…

百度文章SEO软文优化是什么意思

hello&#xff0c;大家好&#xff0c;我是百收编辑。今天来分享一下如何用 SEO 的方式获取各平台的精准搜索流量&#xff0c;来做自己的私域流量增长。关于我以前最开始主要是从百度上去获取我们说的精准搜索流量&#xff0c;接下来就是从百度转到了微信&#xff0c;尤其是在微…

自媒体seo是啥?怎么做自媒体seo来搞流量?

hello&#xff0c;大家好&#xff0c;我是百收SEO OK&#xff0c;今天给大家分享一下。自媒体 SEO 怎么做&#xff1f; OK 好。要说自媒体SEO&#xff0c;必须先说一下三个概念&#xff0c;第一个自媒体&#xff0c;第二个SEO&#xff0c;第三个自媒体SEO。我们首先说自媒体&am…

网站开发制作收费标准(网站开发费用价目表)

网站开发制作收费标准(网站开发费用价目表)#网站#网站开发#网站建设#网站多少钱 需要多长时间&#xff1f;备案的时间周期是不是建立公司所能控制的&#xff1f;大家好&#xff0c;我是郑国&#xff0c;欢迎大家观看我的视频分享。最近我们有一个客户&#xff0c;备案已经提交了…

开发网站商城备案一般需要多久时间?

开发网站商城备案一般需要多久时间?#网站建设#开发网站#网站备案 高端的企业网站都有哪些特点&#xff1f; 1、页面布局简单大方。对比一般网站&#xff0c;高端网站的页面布局会精心设计&#xff0c;简单大方&#xff0c;导航栏一目了然&#xff0c;页面上也不会有过于复杂的…

专转本校园资讯网站(BM25相似性匹配算法)

专升本是提升自己专科学历到达本科阶段的一个方法和手段&#xff0c;考试成功之后就读两年就是本科的学历了&#xff0c;对于大多数的学生来说还是很有必要和帮助的。对于有决心考上专升本的学生以及愿意在这期间努力付出的学生而言&#xff0c;成功考上专升本以后就读两年是非…

网站收藏夹

2019独角兽企业重金招聘Python工程师标准>>> 时尚类 http://www.shoptiques.com 旅游类到到 http://www.daodao.com/ 电子商务 返利网http://www.ebates.com/ 转载于:https://my.oschina.net/lilugirl2005/blog/169259

高负载网站架构图

非本人所设计, 但也找不到作者了.转载于:https://www.cnblogs.com/silvester/archive/2009/04/21/1694657.html

国人当自强:两岸三地在线编程学习网站大搜罗

国人当自强&#xff1a;两岸三地在线编程学习网站大搜罗 发表于2013-12-13 18:30|81289次阅读| 来源CSDN|338 条评论| 作者唐小引移动开发网站在线教育Fenby麦可网开课吧多贝网优才网玩编程MOOC摘要&#xff1a;在本文中&#xff0c;我们介绍了来自两岸三地的编程学习网站&…

SEO(搜索引擎优化)网站优化排名最重要的是什么

SEO&#xff08;搜索引擎优化&#xff09;是网站优化的一个重要步骤&#xff0c;它能让你的网站在搜索引擎中有更好的排名&#xff0c;从而获得更多的流量。但是要想获得高质量的流量需要进行一定程度上的优化&#xff0c;以便大家能找到你的网站。 SEO优化基本上可以分成两部分…

自学网站

1.我要自学网 2.黑马程序员 IT资源 3.办公资源 PPT资源 4.爱思英语 5.学识网 各行各业的文章 6.SEO自学网 搜索引擎优化 7.PS自学网 8.大家论坛 综合性资源&#xff0c;包括考试、考证方面资源&#xff0c;论坛 9.慕课网 IT资源 10.第一教程网 综合资源&#xff0c;包括电脑基础…

公众号如何涨粉?做微信seo疯狂涨粉技巧

无论是做什么项目&#xff0c;还是卖什么产品&#xff0c;都需要流量&#xff0c;而流量有很多种获取的方法。 今天就以减肥粉为案例讲一下微信seo引流的方法&#xff0c;只要你坚持操作了&#xff0c;日引100流量绝对是可以的。 现在微信搜一搜的流量是非常巨大的&#xff0…

python 3 爬取某小说网站小说,注释详细

目标&#xff1a;每一个小说保存成一个txt文件 思路&#xff1a;获取每个小说地址&#xff08;图一&#xff09;&#xff0c;进入后获取每章节地址&#xff08;图二&#xff09;&#xff0c;然后进入获取该章节内容&#xff08;图三&#xff09;保存文件中。循环 效果图&#x…

Vue + TypeScript + Element 项目实践(简洁时尚博客网站)及踩坑记

前言 本文讲解如何在 Vue 项目中使用 TypeScript 来搭建并开发项目&#xff0c;并在此过程中踩过的坑 。 TypeScript 具有类型系统&#xff0c;且是 JavaScript 的超集&#xff0c;TypeScript 在 2018年 势头迅猛&#xff0c;可谓遍地开花。 Vue3.0 将使用 TS 重写&#xff0c;…

第2章 大型网站架构模式

2019独角兽企业重金招聘Python工程师标准>>> ##2.1 网站架构模式## 为了解决大型网站面临的高并发访问&#xff0c;海量数据处理&#xff0c;高可靠运行等一系列问题与挑战&#xff0c;大型互联网公司在实践中提出了许多解决方案&#xff0c;以实现网站高性能&#…