ESModule&Webpack&npm_02


coderwhy老师讲的细,内容多,更有利于我们的学习职业发展,而不是单纯整一个流水线开发程序员出来。

commonjs只在node中可以实现,在浏览器中是不行的,比如让同一个页面的不同区域模块化。

浏览器如何支持esmodule?

946

方法一就是这个浏览器支持esmodule

方法二就是使用webpack打包工具,使用了webpack后我们甚至可以commomjs和esmodule混用,因为最后webpack会把这些我们写的代码解析整合为普通的js代码(就是没有使用模块化),这样不管浏览器支持与否,都能使用了。

认识ESModule

947

注意esmodule中的导出export是没有s的,commomjs中的导出module.exports有s

esmodule会自动采用代码严格模式use strict

方法一ESModule的基本使用

foo.js

const name = "why"
const age = 18

function sayHello() {
  console.log("sayHello")
}

// 导出 export
export {
  name,
  age,
  sayHello
}

在commomjs中是module.exports={}也就是等于一个对象来导出

但是esmodule中这里并不是一个对象,而是特殊的语法,你把导出的变量标识符写到export{}里面就好了。

main.js

// 导入 import
// 注意事项一: 在浏览器中直接使用esmodule时, 必须在文件后加上后缀名.js
//不像commonjs不加后缀有查找机制,但是后续用webpack了也不需要加后缀名会补全
import { name, age, sayHello } from "./foo.js"

// const name = "main"

console.log(name)
console.log(age)
sayHello()

index.html

这里为什么有html?因为esmodule是执行在浏览器中的,原先的commomjs是执行在node中的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <!-- 注意事项二: 在我们打开对应的html时, 如果html中有使用模块化的代码, 那么必须开启一个服务来打开 -->
  <script src="./foo.js" type="module"></script>
  <script src="./main.js" type="module"></script>

</body>
</html>

这里引入js的时候必须写type=“module”只有这样浏览器才知道它是一个模块化的js,有自己独立的作用域,否则会变量冲突(如foo.js和main.js定义同一个名字变量)。

注意

打开index.html必须开启一个服务,也就是open with live server(vscode里面的live sever插件),不能用open in default browser

948

因为模块化的js导入的时候,存在一个cors跨域问题,不支持本地的file请求,必须开启一个服务用http等协议。

Cors的英文全称是Cross-origin Resource Sharing,意思是跨域资源共享

其他导出方式

// 3.导出方式三:
export const name = "why"
export const age = 18

export function sayHello() {
  console.log("sayHello")
}

export class Person {}

// console.log(name)

// 1.导出方式一: 
// export {
//   name,
//   age,
//   sayHello
// }

// 2.导出方式二: 导出时给标识符起一个别名
// export {
//   name as fname,
//   age,
//   sayHello
// }

当mainjs从foojs中导入了一个name变量,mainjs也需要自己定义一个name变量怎么办呢?就可以用到导出方式二,把foojs中的name起别名为fnam

我们也可以导出方式三,在变量,函数等在定义的时候就export导出,但是这样就不能起别名。但是可以在导入的时候起别名

import { name as fname, age, sayHello } from "./foo.js"

问题

import { name, age, sayHello } from "./foo.js"

每次导入这样写一大堆变量,万一需要导入的很多,不难写吗?

所以我们可以直接写导入*代表全部的意思,然后给它一个别名,就可以用别名来使用

// 3.导入时可以给整个模块起别名
import * as foo from "./foo.js"

const name = "main"

console.log(name)
console.log(foo.name)
console.log(foo.age)
foo.sayHello()

export和import的结合使用

开发中用的不多,但是一些优秀项目或者框架的源码经常这样写

作用:不需要在main.js中导入多个js了,只需要导入一个indexjs

mainjs

// import { formatCount, formatDate } from "./utils/format.js"
// import { parseLyric } from "./utils/parse.js"

import { 
  formatCount, 
  formatDate, 
  parseLyric 
} from './utils/index.js'

console.log(formatCount())
console.log(formatDate())

console.log(parseLyric())

indexjs

import { formatCount, formatDate } from './format.js'
import { parseLyric } from './parse.js'

export {
  formatCount,
  formatDate,
  parseLyric
}

// 优化一:
// export { formatCount, formatDate } from './format.js'
// export { parseLyric } from './parse.js'

// 优化二:
// export * from './format.js'
// export * from './parse.js'

default用法

一个模块(也就是一个js文件)只能一个默认导出,导入的时候不需要写导入的变量或函数的名字

import parseLyric from "./parse_lyric.js"
console.log(parseLyric())

这里的parseLyric名字乱下都可以,因为是默认导出,比如写为import demo from “./parse_lyric.js”那么使用的时候就是demo()

其实我感觉是多此一举,又要理解一个东西,只要了解一下有人才这样写我们也知道是什么东西

//导出
// 2.定义标识符直接作为默认导出
export default function() {
  return ["新歌词"]
}

import的一些注意

tips:路径是不允许去+拼接的

1-导入语句只能写在代码顶层,不能放在任意的代码语句内,如if条件成立再import导入

因为js引擎解析执行的时候设定的就是先扫描有没有import,如果有就导入后再执行后续代码,你在后续代码里面写个import会直接报错的

949

如果我就是要语句成立再导入呢?不然我没用到也导入不是浪费性能?

那我们可以使用import函数,以前的写法是import声明。

950

import meta

951

不怎么用,也就是说哪个js中import了其他模块,这个js中就有一个import.meta属性,可以打印出来,里面记录的引入的模块变量来自哪个url地址路径

ESModule的解析过程

http://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/

了解即可,coderwhy的2022系统课面向25k,内容确实细。

952

953

npm的介绍和基本使用

954

比如尤雨溪开发了vue框架

1-如果我们开发者要使用,可以通过vue官网或者github尤雨溪的主页去下载vue.js等文件,然后放到我们项目的lib中,然后再script引入,这样太麻烦了,如果我们要更换版本还得重新下载引入。

2-尤雨溪把vue.js放在了npm registry ,那么我们只需要通过npm就可以快速下载引入。

955

npm包管理工具

官网npmjs.org

tips:“.org”域名是互联网的通用顶级域之一,英文全称organization”,意思为“组织”,适用于各类型组织机构,包括非盈利团体,是组织机构的首选。

npm就是node package manager,刚开始是主要管理node包的,现在在前端项目中也都可以使用。

956

当我们在vscode控制台,进入指定目录,输入命令如node install vue ,那么对应目录就会自动生成一个node_modules文件夹,vue的源码就会被下载到这里。

同时在当前目录还会生成package.json和package-lock.json

package配置文件

json的几种格式https://blog.csdn.net/weixin_48185778/article/details/109822965

一个完整的项目,通常会有项目名称,版本号,以及依赖那些库等等信息保存在package.json

如何生成的?

1-手动创建,缺点:写的太麻烦

2-在控制台输入npm init 命令自动生成只需要我们自己填写一些信息。如果所以信息默认可以输入命令

npm init-y

957

3-通过脚手架CLI快速创建项目,会自动生成package.json

958

常见的属性

960

959

在很多项目中,我们通过require(day)引入后,其中day的目录中是没有index.js的,所以commomjs的自动寻找机制就找不到,main属性就可以设置这个入口,让require去找mian属性值的文件。

965

scripts

961

当我们要经常运行一段命令行,可以直接把它写入scripts字段内,然后通过npm run的方式运行。

dependencies字段

962

1-当我们的同事需要在我们项目的基础上写代码什么的,我们传给同事项目一般会把node_modules删掉再压缩发给他们,因为node_modules里面通常有很多包入axios,vue等等等非常大。

2-那么同事拿到我们的代码,要想跑项目,必须再重新下载以上依赖包,dependencies就能告诉他以及node,这个项目需要哪些包,他可以自己一个一个下载,也可以在node终端执行node install命令会自动下载当前项目所需所有包。

devDependencies字段

963

1-也就是说在开发的时候需要用到,生产product的时候不需要用到的包,放到devDependencies字段中,如webpack就是一个在开发的时候打包的,后续在浏览器等生成页面的时候不需要用到它。

2-安装webpack的时候我们要写npm install webpack –sava -dev命令或者这段命令的缩写npm install webpack -D,就可以自动添加devDependencies字段中

peerDependencies

当一个库必须依赖另一个库才能使用跑起来,就需要把另一个库写入到peerDependencies字段

964

如上图的element-plus这个库,它是基于vue3的,你想使用element-plus,必须当前环境中也有vue3

版本号

966

如vue3无法再写vue2的一些语法,不兼容了就是主版本号

只是新加了一个功能,就是次版本号

修复了一些bug,优化一下,就是z修订号。

了解

967

npm install原理

1-npm和node和java等等在cmd命令行的命令,都需要配置环境变量,当我们输入了命令,会通过环境变量去找到对应的程序执行,也就是说你也可以配置一个qq的环境变量,然后在cmd中输入qq自动启动。

968

1-那些我们所有项目都要用到的工具包,比如webpack就全局安装,那些只在当前项目使用的包如day.js就局部安装即可(安装到当前安装路径下)

2-并不是你全局安装了包,比如全局安装了dayjs和axios,就能每个项目都能使用了,这种包必须局部安装到项目文件夹内。

969

1-上面说过了开发依赖就是我们程序员写程序的时候需要用到的包,浏览器等平台渲染的时候用不到,如webpack

2-生产开发依赖就是,开发的时候和浏览器渲染的时候都要用到这个包,比如vue

缓存共用开发包

1、使用cnpm install时候,并不会生成 package-lock.json 文件,也不会根据 package-lock.json 来安装依赖包,还是会使用 package.json 来安装。
2、package-lock.json 是在 npm(^5.x.x.x)后才有

package-lock.json 它会在 npm 更改 node_modules 目录树 或者 package.json 时自动生成的 ,它准确的描述了当前项目npm包的依赖树,并且在随后的安装中会根据 package-lock.json 来安装,保证是相同的一个依赖树,不考虑这个过程中是否有某个依赖有小版本的更新。官方是这样解释的

它的产生就是来对整个依赖树进行版本固定(锁死)。

当我们在一个项目中npm install时候,会自动生成一个package-lock.json文件,和package.json在同一级目录下。

package-lock.json记录了项目的一些信息和所依赖的模块。这样在每次安装都会出现相同的结果.。不管你在什么机器上面或什么时候安装。

当我们下次再npm install时候,npm 发现如果项目中有 package-lock.json 文件,会根据 package-lock.json 里的内容来处理和安装依赖而不再根据 package.json。

也就是说package.json里面的依赖,npm install通过这个去下载,只会保证大版本一样,后面的小版本是可能改变的(自动下载最新),如果是package-lock.json就指定什么版本就是什么版本,不会改变。

如果多个项目,都用axios而且版本一样,那么npm就不会去请求仓库地址,而是先看本地有没有这个包,如果有就直接安装,没有再去请求下载。

970

resolved字段代表了当前包从哪个url下载下来的

requires字段和dependencies是一样的作用,指当前包依赖哪些包才能正常运行使用

integrity是当前包的一个标识,缓存包就是通过它来识别的。

971

1-也就是说如果这个项目有lock,比如下载那么执行npm install就会通过lock去找需要的包,然后再判断一下现在这个包的所需依赖和以前是不是一样,如axios以前只依赖redirect,现在又加了form-data,一样的话就去缓存查找有没有这个axios的缓存,然后安装,没有缓存的话就要去仓库下载。

2-如果这个项目我们拿到没有lock的话,就只能去仓库下载,然后会自动构建一个lock包,供后续人的使用。

npm的其他命令

972

yarn

以前npm不好用,各大厂如谷歌脸书就一起推出了一个js包管理工具yarn,后续npm5改进了很多小问题,它们两个的用户就分庭抗礼了。

想安装yarn,用npm下载即可,因为工具包一般每个项目都要使用,所有得-g全局

npm install yarn -g

yarn的命令与作用和npm基本上一样的,就是把npm改成yarn

973

cnpm

974

cnpm其实就是npm的中国版,完全一样的东西,就是命令把npm改成cnpm

作用:

npm里面可能有的包服务器在国外,你不科学魔法上网上不去,这个时候有三个解决办法

1-科学上网

2-改npm的下载镜像,但是镜像中的包比较不是官方的,我只想在包下载不了的时候用镜像,就得改来改去

3-安装cnpm,把cnmp的镜像改成国内的镜像站地址如taobao的,平时用npm,如果有包下载不了再用cnpm


文章作者: 瑾年
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 周东奇 !
免责声明: 本站所发布的一切内容,包括但不限于IT技术资源,网络攻防教程及相应程序等文章仅限用于学习和研究目的:不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。本站部分信息与工具来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如有侵权请邮件(jinnian770@gmail.com)与我们联系处理。
  目录