给非前端朋友的前端知识学习引导

2,647 阅读12分钟

推荐阅读

Vue3源码

微前端源码

React18源码

欢迎关注微信公众号:杨艺韬
更多前端源码剖析相关内容

有些非前端朋友希望介入一些前端的工作,可以参考本文,拟定一个初步的学习计划

大纲

  • 现代前端的本质
  • 前端工具链的脉络
  • 参与基础开发需要掌握的最小知识量
  • 介入实际开发工作的步骤

现代前端的本质

前端的原始形态

所需知识:html(页面元素) + css(页面元素的样式效果) + javascript(动态对元素增删改查,动态调整样式)

我们通过浏览器查看页面源码或者审查元素,可以直观的体验前端的原始形态。

示范

新建文件hello.html,在编辑器中输入下面的内容:

<!-代码片段1-->
<html>
    <head></head>
    <body>
        <div id="root"> hello world</div>
    </body>
    <script>
        setTimeout(()=>{
           document.getElementById("root").innerHTML = "修改过后的 hello world" 
        },3000)
        
    </script>
</html>

输入完成后保存文件,在浏览器中打开这个页面,会发现页面上会展示hello world,在3秒钟后,页面展示的内容变化为修改过后的 hello world。 通过上面的体验,我们可以发现这样的前端程序有两个明显的特点:

特点一: 编写的代码不需要任何额外的处理,浏览器马上可以解析执行,程序只包含浏览器能识别的html标签和js代码(为了程序简洁,这里没写css相关代码)。

特点二: 如果要修改页面上的内容,需要先直接操作DOM节点。举个例子,如果我们从服务器请求了一个很长的列表数据,我们需要手动根据这些数据创建不同的DOM节点,然后挂在到页面中去。这个过程如果处理的好,可以性能优良的运行,如果处理不好极有可能产生性能问题,同时编码复杂度会增加。

现代前端

所需知识:html + css/less/scss + javascript + (vue、vuex、pinia、 vue-router...)/react/angular + node + webpack/vite/rollup + babel + ...

从所需知识来看,现代前端需要掌握大量的知识,下面我们以vue2.6为例(实际工作中很多旧项目用的还都是vue2.6,所以没用vue3或react来举例),实现一个和代码片段1类似的功能。新建文件hello.vue,输入下面内容:

// 代码片段2
<template>
    <div>{{textStr}}</div>
</template>
<script>
export default {
    data(){
        return {
            textStr:'Hello World'
        }
    },
    mounted(){
        setTimeout(()=>{
            this.textStr = '修改过后的 Hello World'
        },3000)
    }
}
</script>
<style lang="less" scoped>
</style>

注:实际上,用vue2.6实现代码片段1类似的功能,可以有很多种不同的写法,但在实际工程项目实践中通常是代码片段2所示的形态。

如果大家了解了html、css、javascript的基础语法,会发现代码片段2虽然看起来和前端程序的原始状态有几分相似,但是实际上是不符合相关语法规范的(比如代码片段2中出现的templateless{{textStr}}等内容,对于浏览器来说都比较陌生),换句话说,浏览器是不能识别代码片段2的相关代码,浏览器只能识别符合html、css、javascript语法规范的程序。

既然我们写的hello.vue不能被浏览器正确识别,毫无疑问我们需要做一件事情: 将浏览器不能识别的内容,转化为浏览器可以识别的内容

那我们需要转化成什么样的内容,浏览器才可以识别呢?

答案其实很简单,转化成符合html、css、javascript相关语法规范的代码即可。以代码片段2为例,我们应该将程序转化成下面两种形式之一: 形式一:使用带编译功能的vue版本,程序内部会解析处理下面template所指向的内容

// 代码片段3
new Vue({
  el:'#root',
  template: '<div>{{helloTest}}</div>',
  data(){
    return {
        helloTest: 'hello world'
    }
  }
})

注:这里代码片段3template对应了代码片段2中的template相关的内容,我们称之为模版vue在底层最终会将这些模版表示的元素转化成真正的html元素。

形式二:提前进行编译处理,将template转化为render函数,只需要运行时的vue版本

// 代码片段4
new Vue({
  el:'#root',
  data(){
    return {
        helloTest: 'hello world'
    }
  },
  render:h=>{
    return h('div',{},[this.helloTest])
  }
})

相较于代码片段3,代码片段4中传给Vue构造函数的参数中没了template属性,多了一个render函数,这个render函数就是由template转化而来,在该render函数的底层,实际上会把模版所对应的内容转化为对应的Javascript对象,我们称这些对象为虚拟DOM,然后再将这些虚拟DOM转化为真实DOM呈现在页面上。

注:Vue的编译时相关代码主要就是将模版转化为render函数,如果这个转化的过程如果体现完成,我们的程序发布到线上环境的时候,我们所引入的Vue.js就可以不用带编译相关功能,这也就是上文形式一形式二根本的不同。

这时我们可能会产生一个疑问: 代码**片段3**和代码**片段4**为什么能被浏览器识别呢? 因为这里的new Vue({...})操作,就是通过new操作符初始化一个Vue实例,而Vue是一个普通的JavaScript构造函数,只不过在初始化的过程中,Vue在内部执行了许多逻辑。

注:所谓学习Vue,就是编写Vue能识别的代码。比如代码片段3中的{{helloTest}},虽然浏览器不识别,但是Vue知道如何将其转化为浏览器能识别的内容。

有了上面的认识,我们可能会产生一个新的疑问: 为什么我们不直接编写成代码片段3或代码片段4的代码,而要写成代码片段2的代码?

答案其实很简单,至少有下面几个原因:

  1. 代码片段3中的template写着体验不好
  2. 代码不好组织管理

到这里,我们已经回答了上面的问题那我们需要转化成什么样的内容,浏览器才可以识别呢?。但新问题是: 我们怎么去转化了呢?怎么把浏览器不识别的代码片段2的内容转化成浏览器能识别的代码片段3或代码片段4的内容?

答案是什么我们先不去深究,但我们这里要知道,肯定是通过一个程序去完成这个转化的过程。那既然是程序,我们可以是C++、Java、Python、Go、Rust等各种各样的程序来实现这个转化的过程,但是在前端生态圈,这些转化程序一般都是通过Javascript编写的。

这会使我们陷入新的疑惑,我们前面不是提到过浏览器可以正确的识别JavaScript程序吗?那我们的这些转化程序不可能是到浏览器上面执行吧?其实从理论上讲,如果非要这么做也是可以实现的,但是这不具备工程实践意义,我们通常是在本地开发的时候就完成了这个转化的过程。既然是在本地开发过程中实现这个转化过程,那我们用JavaScript编写的转化程序怎么才能执行呢?请看下文。

前端工具链的脉络

前端工具链的基石 - Node.js

Node是什么

Node是一个基于Chrome V8引擎的JavaScript运行环境。

能够解析javascript,调用操作系统的能力,比如文件读取,端口监听等等。这其实也就回答了上文关于如何在非浏览器环境下执行JavaScript程序的问题。

注:推荐nvm管理Node环境

有了执行JavaScript程序的平台,那我们到底用哪个程序来转化呢,将浏览器不认识的hello.vue转化成浏览器可以识别的内容。答案是多样的,webpack、vite、esbuild、rollup...都是行业知名的前端程序构建工具。其实准确的讲,转化的过程来讲并不是由这些工具来实现的,而是在这些工具所属的体系下,集成某些能力来进行转化。甚至于我们可以自己编写一些特定的程序来进行特定的转化,但这在实际工作中不太普遍。鉴于工作中有很多项目还在用webpack,本文以webpack来简要介绍。

webpack

webpack的本质 可以这样来简单的理解其核心工作。webpack以一个入口文件开始,把相互依赖的js、css集成在一起(当然也可以按规则拆分),产生出诸如xxx.jsxx.css的文件嵌入一个所配置的html文件中。 webpack官网是这样解释的:

At its core, webpack is a static module bundler for modern JavaScript applications.

webpack作为一个通用的前端程序构建工具,会在多种场景下工作,比如在js文件中遇见代码import HelloWorld from './helloworld.vue', 正常也是无法识别的。但webpack提供了可扩展的机制,其中loaderpluginwebpack两个重要的概念,对于文件的识别一般通过loader来实现。比如对于vue而言,就有vue-loader来进行处理,至于vue-loader具体如何工作,大家可以读完本文后去查阅相关资料了解。

上面描述了那么多的内容来进行程序的转化,一个新问题可能从脑海中浮现: 既然经历了复杂的过程,最终还是要转化成前端程序的原始状态,那为什么要用Vue来写程序?

  1. 很少去手动操作DOM,专注于数据层面的变化,提高开发效率;
  2. 可以配合前端工具一定程度上提高兼容性处理的效率(如高版本js代码转低版本--bable);
  3. 给了特定的开发范式,代码可读性可维护性增强(组件化,css预处理等等);
  4. 完善的生态系统,可直接使用的成熟的库。

其实有了上面的知识,我们已经可以进行程序的开发了,但是还有许多工程实践问题需要我们处理:怎么对项目进行管理,具体的,比如怎么引入依赖,怎么启动项目??

如果没有工具,我们需要手动下载一些依赖包放到某个地方去,然后通过特定的路径去导入引用,这样做的效率会很低,同时繁琐且容易出错。这时我们需要借助一些程序的包管理工具。行业中有npm、yarn、pnpm...等很多优秀的工具,本文以npm为例进行介绍。

包管理工具——npm

安装、卸载、更新...

npm intall xxx # 安装什么依赖包,依赖包从哪里来,安装到哪里去,安装了怎么用
npm uninstall xxx
npm run xxx # 执行什么指令

package.json 一个npm用的包管理配置文件,记录了诸多信息,参看npm官方文档

node_modules package.json对应的目录下会自动创建改目录,存放下载的安装包

模块

import {xxx} from 'xxx'
import Xxx from 'xxx'

本质上就是引入了一个js文件中的某些暴露的方法或对象

注:推荐nrm工具来切换npm镜像源

当前需要掌握的知识

  1. js的基本语法《JavaScript权威指南》;
  2. vue基本语法、vuex/pinia、vue-router等等;
  3. node、npm 基本环境的配置,webpack的简单应用;
  4. 组件库 element-ui的了解。

有了上面的知识,可以支撑我们从事一些普通的管理后台系统的开发。

介入开发的工作安排

  1. 掌握上面的基础知识;
  2. 有兴趣的伙伴阅读项目代码,基本了解并将项目跑起来尝试写些代码;
  3. 自己评估,如果有信心就可以进入开发了;
  4. 建议
    1. 开发新功能,尽量不改旧功能,因为历史原因,有些代码相互关联很容易出错;
    2. 前期评估时间尽量充裕些,前期提交的代码最好CodeReview下,适应一段时间自己提交自己改bug;
    3. 可以网上找点教程听一听,不过需要注意公司实际项目中用的是Vue2还是Vue3又或者是React,别学错了。

更多前端文章,欢迎访问我的掘金主页