ES Module使用-原理-包管理工具npm(一)

简介: ES Module使用-原理-包管理工具npm

ES Module使用-原理-包管理工具npm

(理解)前端使用模块化的方案解析

  • es modules
  1. ECMA2015提出模块化规范
  2. 必须浏览器本身支持es modules才能够使用


  • webpack 模块化打包工具
  1. 如果浏览器不支持的话我们可以通过webpack进行打包,这样就算浏览器不支持也能够进行使用,因为webpack内部已经做出处理了。后续我们也会写webpack内部是怎么实现的


认识 ES Module

  • JavaScript没有模块化一直是它的痛点,所以才会产生我们前面学习的社区规范:CommonJS、AMD、CMD等,所以在ECMA推出自己的模块化系统时,大家也是兴奋异常
  • ES Module和CommonJS的模块化有一些不同之处:
  • 一方面它使用了importexport关键字
  • 另一方面它采用编译期的静态分析,并且也加入了动态引用的方式
  • ES Module模块采用export和import关键字来实现模块化:
  • export负责将模块内的内容导出
  • import负责从其他模块导入内容;
  • 了解:采用ES Module将自动采用严格模式:use strict

(掌握)ESModule的基本的导入导出

案例代码结构组件

  • 这里我在浏览器中演示ES6的模块化开发:
<script src="./modules/foo.js" type="module"></script>
<script src="main.js" type="module"></script>
  • 如果直接在浏览器中运行代码,会报如下错误:(不开启本地服务)

image.png

  • 这个在MDN上面有给出解释:
  • 我这里使用的VSCode插件:Live Server

exports关键字

  • export关键字将一个模块中的变量、函数、类等导出;
  • 我们希望将其他中内容全部导出,它可以有如下的方式:
  • 方式一:在语句声明的前面直接加上export关键字
  • 方式二:将所有需要导出的标识符,放到export后面的 {}中
  • 注意:这里的 {}里面不是ES6的对象字面量的增强写法,{}也不是表示一个对象的
  • 所以: export {name: name},是错误的写法;
  • 方式三:导出时给标识符起一个别名
  • 通过as关键字起别名
//方式2
//定义的时候就直接导出了,这种方式不能起别名,但有时候反而更加方便
export const name = "小余"
export function sayHello(){
    console.log("你好啊")
}
export class Person{
    
}
//方式3
//导出取别名
exports {
    name as fname//要导出本文件的name,取别名为fname
}
//导入
import {fname} from "./xxx"
//为什么这么做?因为导入怕原先变量名跟当前文件的变量名有冲突,而直接修改导入文件的变量名又会突兀又麻烦,所以在导出的时候就采用取别名的方式

import关键字

  • import关键字负责从另外一个模块中导入内容
  • 导入内容的方式也有多种:
  • 方式一:import {标识符列表} from '模块';
    注意:这里的{}也不是一个对象,里面只是存放导入的标识符列表内容
import {} from "./xxx"//常用


  • 方式二:导入时给标识符起别名
    通过as关键字起别名
//刚刚导出的第二种方式无法在导出的时候起别名,那就可以在导入的时候起别名
import {name as myName} from "./xxx"//常用
//这种起别名方式更常用


  • 方式三:通过 * 将模块功能放到一个模块功能对象(a module object)上
//*就全部导入的意思,as foo就是给*起别名
import * as foo from "./foo.js"//特殊情况使用


(掌握)ESModule的导入和导出方式扩展export和import结合使用

  • 补充:export和import可以结合使用
//原写法
import {sum} from "./bar"
export{sum}
//优化写法1,两步省略到一步,随着使用次数的增加,省略的就会越明显,也更简洁(阅读性强),推荐这种
export { sum as barSum} from "./bar.js"//导出来自./bar.js的sum,并起别名为barSum
//优化写法2,导入多个内容直接超级简写(简洁性强)  有总结工具文档的话使用这种
export * form "./bar.js"//导出来自./bar.js的所有内容
  • 为什么要这样做呢?
  • 在开发和封装一个功能库时,通常我们希望将暴露的所有接口放到一个文件中(比如放到index.js里面)
  • 这样方便指定统一的接口规范,也方便阅读
  • 这个时候,我们就可以使用export和import结合使用

而且我们专门拿出一个文件用来存放导入的东西的时候,就不用到处翻来翻去的了,使用的都是统一在index.js里面,甚至文件名都可以直接省略掉,而是填入文件夹名,文件夹名就会自动推导去找自身里面的index.js,非常的科学规范

(理解)ESModule的导入和导出结合使用

default用法

  • 前面我们学习的导出功能都是有名字的导出(named exports):
  • 在导出export时指定了名字
  • 在导入import时需要知道具体的名字

其实也可以不指定名字的,后续到webpack的时候再来进行讨论

  • 还有一种导出叫做默认导出(default export)
  • 默认导出export时可以不需要指定名字
  • 导入时不需要使用 {},并且可以自己来指定名字
  • 它也方便我们和现有的CommonJS等规范相互操作
  • 注意:在一个模块中,只能有一个默认导出(default export)
//xiaoyu文件
function parseLyric(){
    return ["歌词"]
}
const name = "小余"
//1.默认导出
export default parseLyric
//2.定义标识符直接作为默认导出(一个模块只能有一个默认导出,这里主要是为了记录所以才写在一起)
export default function(){//直接默认导出甚至可以不起函数名字,而是由导出的那方去决定名字
    return ["十万八千梦"]
}
//在另一个文件中导入
import aaaa from "./xiaoyu"//这个aaaa是随便起的名字,由于是默认导出的方式,所以取名是什么在我们导入的时候可以随便起

(掌握)ESModule的默认导出和导入

import函数

模块要放在js最顶层的,不允许在逻辑代码中编写import导入。


而且顶层的import引入的路径是不能够拼接的



  • 因为顶层模块是最先执行的,优于代码的执行,所以当模块开始执行的时候,字符串是还没有拼起来的,所以会报错
//错误做法
import {name,age} from ("./foo"+".js")
  • 通过import加载一个模块,是不可以在其放到逻辑代码中的,比如:
  • 为什么会出现这个情况呢?
  • 这是因为ES Module在被JS引擎解析时,就必须知道它的依赖关系
  • 由于这个时候js代码没有任何的运行,所以无法在进行类似于if判断中根据代码的执行情况
  • 甚至拼接路径的写法也是错误的:因为我们必须到运行时能确定path的值
  • 但是某些情况下,我们确确实实希望动态的来加载某一个模块:
  • 如果根据不懂的条件,动态来选择加载模块的路径(就是逻辑成立,我们才导入某个模块)
  • 这个时候我们需要使用 import() 函数来动态加载

import函数返回一个Promise,可以通过then获取结果

const flag = "作者是xiaoYu"
if(flag){//满足逻辑
    // const importPromise = import("./foo.js")
    // importPromise.then(res => {
    //     //import()返回的是一个Promise,所以我们可以这样来决定处理
    // })
    //简写
    import("xiaoyu").then(res =>{
      console.log("你说对了,作者是:",res);
    })
}

import meta

  • import.meta是一个给JavaScript模块暴露特定上下文的元数据属性的对象。
  • 它包含了这个模块的信息,比如说这个模块的URL
  • 在ES11(ES2020)中新增的特性

(理解)ESModule的解析过程和原理

ES Module的解析流程

  • ES Module是如何被浏览器解析并且让模块之间可以相互引用的呢?
  • ES Module的解析过程可以划分为三个阶段:
  • 阶段一:构建(Construction),根据地址查找js文件,并且下载,将其解析成模块记录(Module Record)
  • 阶段二:实例化(Instantiation),对模块记录进行实例化,并且分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址(模块环境记录Module environment record)
  • 阶段三:运行(Evaluation),运行代码,计算值,并且将值填充到内存地址中

阶段一:构建阶段

  1. 首先从服务器下载下来js文件,然后script的src进行fetch(获取),使用type="module"当作模块去解析
  2. 解析成Module Record,然后在这中途这个js文件解析出来的里面引入了counter.js和display.js文件,然后就又从去fetch(获取)下来,然后解析(parse)生成两个Mudule Record
  3. 然后还会继续检查这两个有没有继续引入,有的话就重复上面的操作,没有的话就结束


MODULE MAP:映射关系

阶段二和三:实例化阶段 – 求值阶段

  1. 查看模块Module Record有没有对这个模块进行导出东西,也就是LocalExport
  2. 有导出就会针对导出的东西生成Module Environment Record(模块环境记录),这里面就记录着我导出的东西,比如图中的count或者render
  3. 然后对count或者render赋值具体值5或者是函数
  4. 然后我们这时候再获取这值就有具体的信息了


(模块环境记录):不是由我们创建出来的,而是由浏览器(JS引擎)生成的,这也就是说我们下面这个不是对象


export{//这个括号不是对象,而是导出的特殊语法,是为了告诉JS引擎我们想要导出哪些内容
  xxx
}

包管理工具详解npm、yarn、cnpm、npx、pnpm

(了解)包管理工具-内容概述

  1. npm包管理工具
  2. package配置文件
  3. npm install原理
  4. yarn,cnpm,npx
  5. 发布自己的开发包
  6. pnpm使用和原理

(掌握)包管理工具-代码共享和npm基本操作

代码共享方案

  • 我们已经学习了在JavaScript中可以通过模块化的方式将代码划分成一个个小的结构:
  • 在以后的开发中我们就可以通过模块化的方式来封装自己的代码,并且封装成一个工具
  • 这个工具我们可以让同事通过导入的方式来使用,甚至你可以分享给世界各地的程序员来使用
  • 如果我们分享给世界上所有的程序员使用,有哪些方式呢?
  • 方式一:上传到GitHub上、其他程序员通过GitHub下载我们的代码手动的引用
  • 缺点是大家必须知道你的代码GitHub的地址,并且从GitHub上手动下载
  • 需要在自己的项目中手动的引用,并且管理相关的依赖
  • 不需要使用的时候,需要手动来删除相关的依赖
  • 当遇到版本升级或者切换时,需要重复上面的操作
  • 显然,上面的方式是有效的,但是这种传统的方式非常麻烦,并且容易出错;
  • 方式二:使用一个专业的工具来管理我们的代码
  • 我们通过工具将代码发布到特定的位置(npm (npmjs.com))
  • 其他程序员直接通过工具来安装、升级、删除我们的工具代码
  • 专业的工具就是npm,yarn,cnpm,npx,pnpm这类
  • 显然,通过第二种方式我们可以更好的管理自己的工具包,其他人也可以更好的使用我们的工具包

包管理工具npm

  • 包管理工具npm:
  • Node Package Manager,也就是Node包管理器
  • 但是目前已经不仅仅是Node包管理器了,在前端项目中我们也在使用它来管理依赖的包
  • 比如vue、vue-router、vuex、express、koa、react、react-dom、axios、babel、webpack等等
  • 如何下载和安装npm工具呢?
  • npm属于node的一个管理工具,所以我们需要先安装Node
  • node管理工具:https://nodejs.org/en/,安装Node的过程会自动安装npm工具
  • npm管理的包可以在哪里查看、搜索呢?
  • npm管理的包存放在哪里呢?
  • 我们发布自己的包其实是发布到registry上面的
  • 当我们安装一个包时其实是从registry上面下载的包

3.24小时整集内容

(掌握)项目的配置文件

npm的配置文件(包工具的使用)

  • 那么对于一个项目来说,我们如何使用npm来管理这么多包呢?
  • 事实上,我们每一个项目都会有一个对应的配置文件,无论是前端项目(Vue、React)还是后端项目(Node)
  • 这个配置文件会记录着你项目的名称、版本号、项目描述
  • 也会记录着你项目所依赖的其他库的信息依赖库的版本号
  • 这个配置文件就是package.json
  • 那么这个配置文件如何得到呢?
  • 方式一:手动从零创建项目,npm init –y
  • 方式二:通过脚手架创建项目,脚手架会帮助我们生成package.json,并且里面有相关的配置(都配置好了)

常见的配置文件

  • npm init #创建时填写信息
    npm init -y # 所有信息使用默认的(比较简单)
  • Vue CLI4创建的Vue3项目(Vue的脚手架)

  • create-react-app创建的react17项目(react的脚手架)

(掌握)项目配置文件-基础字段

常见的属性

  • 必须填写的属性:name、version

属性

意思

name

项目的名称

version

当前项目的版本号

description

描述信息,很多时候是作为项目的基本描述

author

作者相关信息(发布时用到)

license

开源协议(发布时用到)

  • private属性:
  • private属性记录当前的项目是否是私有的;
  • 当值为true时,npm是不能发布它的,这是防止私有项目或模块发布出去的方式
  • main属性:
  • 设置程序的入口
    比如我们使用axios模块 const axios = require('axios');
    如果有main属性,实际上是找到对应的main属性查找文件的(就不会默认找到index.js、json、node文件去了)
  • 就引入的时候直接输入main的名字,而不是完整路径了(更加简洁,也是基本的操作)

(掌握)项目配置文件-项目依赖

  • scripts属性
  • scripts属性用于配置一些脚本命令,以键值对的形式存在;
  • 配置后我们可以通过 npm run 命令的key来执行这个命令
  • npm start和npm run start的区别是什么?
    它们是等价的
    对于常用的 start、 test、stop、restart可以省略掉run直接通过 npm start等方式运行(你自己定义的就不能省略run)
"scripts": {
    "start":"运行文件的路径"
  }
//运行快捷键 npm run start
  • dependencies属性
  • dependencies属性是指定无论开发环境还是生产环境都需要依赖的包
  • 通常是我们项目实际开发用到的一些库模块vue、vuex、vue-router、react、react-dom、axios等等
  • 打包npm run build还有vue代码是因为我们还需要依赖vue来操作DOM
  • 与之对应的是devDependencies
  • devDependencies属性
  • 一些包在生产环境是不需要的,比如webpack、babel等(打包完就不需要了)
  • 这个时候我们会通过 npm install webpack --save-dev,将它安装到devDependencies属性中
  • devDependencies = development Dependencies(开发依赖)

//开发环境依赖
npm install xxx --save-dev//全写
npm install xxx --D//简写


  • peerDependencies属性
  • 还有一种项目依赖关系是对等依赖,也就是你依赖的一个包,它必须是以另外一个宿主包为前提
  • 比如element-plus是依赖于vue3的,ant design是依赖于react、react-dom
//在element-plus中就能看到
"perrDependencies":{
    "vue":"版本"
}//这表示必须有Vue才能够使用


ES Module使用-原理-包管理工具npm(二)https://developer.aliyun.com/article/1470452

目录
相关文章
|
1月前
|
JavaScript Linux 数据安全/隐私保护
node内网安装npm私服以及依赖包上传发布verdaccio
node内网安装npm私服以及依赖包上传发布verdaccio
190 1
|
6天前
|
安全 JavaScript 前端开发
怎么发布npm包?
该文介绍了如何在JavaScript环境中发布npm包的步骤。首先,确保npm客户端配置使用官方源,以避免安全和兼容性问题。接着,登录npm账号。然后,检查`package.json`文件,其中包的`name`应唯一,版本号遵循语义化版本控制。更新版本号后,使用`npm publish`发布包。最后,通过在新环境中全局安装并测试包来验证发布是否成功
|
23天前
|
前端开发 JavaScript 数据安全/隐私保护
从0到1开发一个自己的npm包完整过程
创建自己的 npm 包涉及六个步骤:1) 注册 npm 账号;2) 使用 `npm init` 初始化项目,确保 package.json 的 name 唯一且 private 为 false;3) 开发项目,可封装 UI 组件、函数库或命令行工具;4) 本地调试,通过 `npm link` 在项目中测试;5) `npm login` 登录账号,可能需切换至官方仓库;6) 使用 `npm publish` 发布项目。注意版本号递增,无意义的包不建议发布。
29 2
从0到1开发一个自己的npm包完整过程
|
26天前
|
JSON 小程序 前端开发
小程序中使用npm安装vant组件实现按需引入减少代码包大小,避免触发用户隐私协议
微信小程序按需引入 vant 组件,自动清除项目中未使用的 vant 组件,减少代码包大小,避免因未使用到的 vant 组件触发隐私协议提交审核时被拒
33 1
小程序中使用npm安装vant组件实现按需引入减少代码包大小,避免触发用户隐私协议
|
1月前
|
缓存
发布第一个npm包的过程记录
发布第一个npm包的过程记录
21 0
|
1月前
|
JavaScript 前端开发 开发者
Node.js的包管理和npm工具深度解析
【4月更文挑战第30天】本文深入解析Node.js的包管理和npm工具。包管理促进代码复用和社区协作,包包含元数据描述文件`package.json`和入口文件。npm提供搜索、安装、发布等功能,通过命令行进行操作,如`install`、`search`、`uninstall`。npm支持版本控制、全局安装、脚本定义及私有仓库。理解和熟练运用npm能提升Node.js开发效率。
|
1月前
|
小程序 开发工具 开发者
【微信小程序】微信开发者工具 引用 vant-weapp时“miniprogram/node_modules/@babel/runtime/index.js: 未找到npm包入口文件” 解决办法
【微信小程序】微信开发者工具 引用 vant-weapp时“miniprogram/node_modules/@babel/runtime/index.js: 未找到npm包入口文件” 解决办法
74 1
message: 没有找到可以构建的 NPM 包,请确认需要参与构建的 npm 都在 `miniprogra
message: 没有找到可以构建的 NPM 包,请确认需要参与构建的 npm 都在 `miniprogra
|
1月前
|
存储 缓存 资源调度
ES Module使用-原理-包管理工具npm(二)
ES Module使用-原理-包管理工具npm
87 0
|
1月前
|
网络安全 计算机视觉
【node】 npm install 报错:code 128
【node】 npm install 报错:code 128
54 1

热门文章

最新文章

推荐镜像

更多