前端工程\模块化

news2024/12/23 5:36:25

前端工程\模块化🏭

本篇文章,学习记录于:尚硅谷🎢,紧接前文:邂逅Node.JS的那一夜→博客

无论是前端、后端、甚至非编程领域都有模块化的概念,只是不同的领域叫法不同,不过,新技术的产生一定是有原因的:

模块化的概念🧊

为什么需要模块化技术: 随着 Web 技术的发展,各种交互以及新技术等使网页变得越来越丰富,前端工程师登上了舞台

同时也使得我们前端的代码量急速上涨、复杂性在逐步增高,越来越多的业务逻辑和交互都放在 Web 层实现

代码一多,各种命名冲突、代码冗余、文件间依赖变大等等一系列的问题就出来了,甚至导致后期难以维护;


编程领域的模块化: 在这些问题上, java、 php 等后端语言中早已有了很多实践经验,模块化

编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块

因为小的、组织良好的代码远比庞大的代码更加理解和维护,于是前端也开始了模块化历程;

模块的化优点✅

  • 可维护性: 模块与模块之间是独立的,一个优秀的模块会让外面的代码对自己的依赖越少越好,这样自己就可以独立去更新和改进;

  • 防止命名冲突: 模块化设计,将系统分解为独立的模块,每个模块都有自己的命名空间,这有助于避免全局范围内的命名冲突;

  • 提高代码复用性: 将代码划分为独立的模块,每个模块负责特定功能。这样的设计使得模块可以在不同的项目中重复使用;

  • 实现代码按需加载、提高团队协作、代码灵活性、降低代码复杂性… … 等: 模块化使前端更易于管理、扩展和维护;

模块化技术发展📶

前端模块化技术的发展历史经历了多个阶段,从最初的零散脚本到现代化的模块系统: 了解即可:

  • Script标签,最简单粗暴的方式:

    早期前端主要使用 <script>标签引入JavaScript,这种方式:存在全局命名空间的问题,容易引起变量冲突,难以维护;

  • 对象模拟命名空间: 为了解决全局命名空间的问题,将相关的函数和变量封装到一个全局对象中,减少了命名冲突的风险;

  • IIFE 和 闭包: ES5 没有块作用域的概念,通过闭包+IIFE 模拟模块封装的效果;

    闭包 Closure:闭包,打破了“函数作用域”的束缚,外部作用域可以访问函数内部的变量,类似Java的get|set

    IIFE Immediately Invoked Function Expression: 是一种将代码块封装在函数中并立即执行的模式,私有作用域|减少全局污染

    //(function(){ IIFE立即执行代码块 })()
    var module = (function(){
      var _count = 0;
      var fn1 = function (){ /** 代码块 */	}
      var fn2 = function fn2(){ /** 代码块 */	}
      //闭包: 暴漏需要暴漏的变量|函数,外部可以访问函数内部的属性|方法;
      return { 	
          fn1: fn1, 
          fn2: fn2,  }
    })()
    
    module.fn1();	// 对象.Xxx 获取闭包暴漏出的fn1;
    module._count; 	// undefined 对于没有暴漏的属性|函数返回undefined;
    

随着时代发展,ES6之前 JavaScript 一直没有体系的 模块化技术

社区开发者们自行制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种,前者用于服务器,后者用于浏览器

  • CommonJS: 使用requiremodule.exports语法来导入和导出模块,主要用于服务器端的模块化技术
  • AMD Asynchronous Module Definition 适用于前端浏览器模块化技术:定义一种异步加载模块的规范,通过RequireJS库实现

模块技术深入人心,官方ECMAScript 2015 ES6的发布: 使用importexport关键字,开发者可以更轻松地组织和导入导出模块;

初体验

经过上述简单的介绍,想必对Node有了一定的了解:内置模块(属于官方领域略…) 此处针对:如何自定义模块——并+导入模块使用 “简单介绍”

Node中的模块概念其本质就是对应一个个Xxx.JS文件,通过模块规范语法进行:属性|函数暴漏 | 模块引入 语法介绍:

  • 暴漏模块数据: module.exports = ???; 用于设置模块中要暴漏的属性|方法,可以暴露任意数据类型;
  • 导入模块: require('模块路径'); 语法和内置模块一样,内容则是要导入模块的相对路径;

自定义模块:moduleOne.js

function fun(){ console.log('通过module.exports 暴漏出函数fun'); }  //声明函数

//model.exports = '设置要暴漏的属性|函数';
module.exports = fun;

自定义模块—之间—导入:mian.js

//通过require('导入自定义模块');
const fun = require('./moduleOne.js');

//调用自定义模块
fun();	

在这里插入图片描述

  • 上述简单介绍: Node中的每一个.js文件都可以理解为模块 ,具有module对象可以通过:module.exports 设置该模块作用域下的属性|函数;
  • 外界的模块想要获取: 则通过 require('自定义模块名路径') 导自定义模块,require(导入模块,返回的值) === 模块 module.exports 值:

module.exports 模块暴漏

上述简单介绍了 moudle: 在每个 .js 自定义模块中都有一个 module 对象,它里面存储了和当前模块有关的信息,.exports 可以暴露任意数据

上述暴漏了一个函数,实际开发中通常一个不仅仅一个属性|函数,.exports可以是任何数据类型所以可以是一个:{ 对象 }

且:require(导入模块,返回的值) === 模块 module.exports 值:

moduleStr.Js: 整个JS文件,直接通过module.exports 暴漏,验证:require(返回值是module.exports的value);

module.exports = "每个.JS文件模块都有一个module对象: require('导入模块,返回值的是module.exports的value')";
{ module.exports = "每个.JS文件只有一个module 即使是 { 作用域块共享同.JS文件的module对象 } 且后来者居上原则..."; }

moduleObj.JS: 通过:module.exports = { Xxx } 自定义模块暴漏多个属性|函数数据;

let funshow = function () { console.log(`我叫${name},外号叫${rname}`); }
let { name, rname } = { name: 'wsm', rname: '5400' };

/** module.exports 支持任何数据类型 { 对象类型 } */
module.exports = { name, rname, funshow, Xxx: '自定义属性...' }	//解构赋值

main.js:

/** require导入自定义模块 */
const mObj = require('./moduleObj');
const mStr = require('./moduleStr');

/** 调用模块属性|函数 */
mObj.funshow();	
console.log(mObj);
console.log(mStr);
我叫wsm,外号叫5400
{ name: 'wsm', rname: '5400', funshow: [Function: funshow], Xxx: '自定义属性...' }
每个JS只有一个module { 作用域块共享一个JS文件的module全局对象 } 且遵循后来者居上原则...

exports.Xxx 模块暴漏

对于模块暴漏,Node还提供第二种写法: exports.Xxx = Value;

moduleExp.js: exports .JS文件中的内置对象可将变量、函数或对象暴漏,以便在其他文件中引用;

  • ⚡注意:⚡ exports 不可以直接赋值: exports = ???使用exports 不可以使用 module.exports优先级高⏫ 下面详细介绍
exports.name = 'wsm';
exports.rname = '5400';
exports.funShow = function () { console.log(`我叫${exports.name},外号叫${exports.rname}`); }

main.js:

/** require导入自定义模块 */
const mExp = require('./moduleExp.js');
console.log(mExp);
mExp.funShow();
{ name: 'wsm', rname: '5400', funShow: [Function (anonymous)] }
我叫wsm,外号叫5400

二者模块暴漏区别:

🆗 经过上述简单了解到了:module.exportsexports 它们都可以暴漏数据,那么二者之间的关系呢:

模块内部 module 与 exports 的隐式关系: exports = module.exports = {}require 返回的是目标模块中 module.exports 的值 😵一下子好晕

  • 所以: exports.Xxx 相当于给 {} 对象上赋值,require 返回的是 module.exports 所以可以获取暴漏的属性;
  • 所以: module.exports优先级高,如果修改了指向,则exports设置的值也就失效了…
  • 所以: exports ≠ value; 不能直接赋值,修改了堆空间指向导致无法暴漏属性|函数;

require 注意事项:

在Node模块化中都是使用 require关键字导入模块: 导入内置模块、传入文件路径即可引入自定义文件模块;

// 加载内置模块方法:
const fs = require('fs');
// 加载自定义模块方法:
const moduleDemo = require('./moduleDemo.js');
/** 暂时省略加载第三方模块: */

对于自定义模块,require 还有一些使用注意事项⚡:

  • 对于自己创建的模块,导入时路径建议写相对路径,且不能省略: ./../
  • .js.json 文件导入时可以不用写后缀,对于同名文件:Xxx.JS|Xxx.JSON .JS优先级更高)
  • c/c++编写的 node 扩展文件也可以不写后缀,但是一般用不到,如果导入其他类型的文件,会以 JS文件进行处理;

main.js: 和 其他自定义模块的暴漏代码;
在这里插入图片描述

//导入多个自定义模块;
const module01 = require('./module01'); //建议使用相对路径,更方便加载自定义模块;
const module02 = require('./module02');
const module03 = require('./module03');
// const module04 = require('./module04');
const module05 = require('./module05.abcd');

console.log(module01);  //module01.JS   .js可以省略后缀
console.log(module02);  //module02.JS   同名文件 js|json JS优先级更大
console.log(module03);  //{ title: 'module03.JSON' }    .json可以省略后缀,并直接返回正JSON内容
// console.log(module04);   //报错: Cannot find module './module04' 非规定文件后缀无法省略后缀
console.log(module05);      //对于其他数据类型则默认以JS进行读写——>——>即: 非规范后缀文件仅识别JS的语法

require 文件夹操作:

require(‘文件夹’) 对于文件夹的导入,会有一些特殊规则,了解即可: 有助于后期的包管理工具学习

  • 如果导入的路径是个文件夹,Node则会首先检测该文件夹下 package.json 文件中 main属性 对应的文件 存在则导入,反之报错

  • 如果 main 属性不存在,或者 package.json 不存在,则会尝试导入文件夹下的 index.jsindex.json

在这里插入图片描述

main.js: require导入文件夹模块

const wsm = require('./wsm');
console.log(wsm);
  • Demo测试: 可以通过:删除package.JS文件文件中的 main:xxx.JS 属性;

require 导入模块流程:

require 导入模块流程相对比较复杂: 这里也仅仅是简单介绍:

  1. 对于核心模块: (httpfs等,直接返回模块;
  2. 非核心模块: 获取导入文件路径,相对路径—>—>绝对路径
  3. 缓存检测: 首先从缓存中查找,如果缓存存在,则直接返回缓存模块,
  4. 缓存不存在: 根据获取的绝对路径|文件夹路径根据规则找到对应的文件,使用FS模块加载该文件并通过:arguments.callee.toString() 查看自执行函数,通过:(function(){})()立即执行函数|执行 最后缓存|返回模块值

NVM 版本控制器

NVM 全称:Node Version Manager node 版本管理工具:

顾名思义它是用来管理 node 版本的工具,方便在同一台设备切换不同版本的 Node

实际开发过程中,经常遇到不同的项目所使用的 Node版本不同,导致开发者需要不停的调整Node版本,NVM就是为了解决这个问题!

NVM 下载|安装

NVM 并不是Node,不会影响Node的任何命令,仅是管理多个Node版本的一个工具: 下载地址

windows系统下载nvm-setup.zip安装包,如果电脑上之前已经安装了node,先卸载,然后解压nvm-setup.zip 双击.exe 进行安装:

  • win+r cmd nvm -v 查看NVM版本🎉🎉 安装成功!!

  • 配置NVM node镜像: 打开nvm的安装目录,找到setting.txt文件:

    arch:64
    proxy:none
    node_mirror:npm.taobao.org/mirrors/node/
    npm_mirror:npm.taobao.org/mirrors/npm/
    

安装注意事项:⚡⚡

  • 安装路径: 不能有中文,可以自定义目录,但貌似程序有时候并不会自动创建nodejs目录,该目录存放Node下载公共module)
  • 环境变量: 默认情况程序会自动配置环境变量,如没有则需手动配置:NVM_HOMENVM_SYMLINKPath
  • NVM命令: 建议使用NVM命令时候,以管理员方式运行CMD,否则报错;

NVM常用命令

  • nvm on :开启node.js版本管理;

  • nvm off :关闭node.js版本管理,关闭|开启 同时会影响Node的使用;

  • nvm list: 显示已安装的版本,* 开头的表示当前使用的版本;

  • nvm list available: 显示所有可以下载的 Node.js 版本;

  • nvm uninstall xx.xx.xx: 删除指定的 Node.js版本;

  • nvm install xx.xx.xx: 安装指定的 Node.js版本;

  • nvm install latest: 安装最新版的 Node.js;

  • nvm use xx.xx.xx: 切换指定的Node.js;

注意:为了避免出错,切换Node版本|使用NVM命令,建议使用管理员模式;

NPM 包管理工具

NPM/包

包是什么:

NodeJS 中的 第三方模块又叫做 第三方模块指的是同一个概念,只不过叫法不同;

由于 Node 的内置模块仅提供了一些底层的 API,导致在基于内置模块进行项目开发的时,效率很低

  • 包是基于内置模块封装开发出来的 ,提供了更高级、更方便的 API, 极大的提高了开发效率
  • 包和内置模块之间的关系,类似于速冻食品本质一样,更方便制作加工;

包的来源: 不同于 Node.js 中的内置模块与自定义模块, 包是由第三方个人或团队开发出来的 ,免费供所有人使用;

注意 :Node.js 中的包都是免费且开源的,不需要付费即可免费下载使用,国外npm, Inc公司: 全球最大的包共享平台!!!

NPM 包管理工具是什么:

NPM 全称 Node Package Manager 翻译为中文意思是『Node 的包管理工具』

NPM 是 NodeJS 内置的包管理工具: 用于NodeJS包的发布、传播、依赖控制、管理已经安装的包

NPM 提供了命令行工具,使你可以方便地下载、安装、升级、删除包,也可以让你作为开发者发布并维护包


前端常见的包管理工具有:

  • npm 是Node.js的包管理工具,广泛用于前端开发,允许开发者安装、共享和管理JavaScript代码包;
  • yarn 由Facebook、Google、Exponent和Tilde等公司共同开发,与npm兼容:提供更快的安装速度、依赖关系管理;
  • cnpm 是一个淘宝镜像提供的用于替代 npm 的客户端工具,主要目的是解决在国内使用 npm 安装包时速度较慢的问题;

NPM 基本使用

Node 在安装时会自动安装 npm 可通过CMD 快速查看版本号:

  • npm -v:查看当前npm的版本号
  • node -v:查看当前Node的版本号

NPM 初始化

使用NPM 进行包管理|项目管理,首先需要项目根目录进行初始化:

  • 在项目的根目录中打开终端: 打开命令行终端,进入你希望创建项目的目录;
  • 运行 npm init 命令: 在终端中执行初始化命令:npm init|npm init -y 跳过手动输入默认信息)
  • 生成 package.json 完成所有提示后,npm init 将生成一个 package.json 文件,并将其保存在项目的根目录中

在这里插入图片描述

🆗通过这个过程,we成功地初始化了一个新的 Node 项目,并创建了一个包含项目基本信息的 package.json 文件;

package.json 文件:

package.json 是 Node 项目中非常重要的配置文件:项目信息、依赖项管理、脚本定义、模块入口定义、开源协议...

{
  "name": "npm01",      //包名  
  "version": "1.0.0",   //包版本
  "description": "",    //包描述
  "main": "index.js",   //包入口文件: 指定项目作为模块时的入口文件;
  "scripts": {          //自动脚本定义: 定义一些命令行脚本,方便执行常见的任务: `npm run Xxx` 执行;
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",         //包作者
  "license": "ISC",    	//开源协议(比较复杂暂时不介绍...
   dependencies: { 		//dependencies 专门用来记录您使用 npm i 安装的包
   },
}
初始化过程注意事项⚡:
  • package.json 支持手动创建与修改

  • version 版本号要求 x.x.x 的形式定义:x 必须是数字,默认值是 1.0.0

  • 可以使用 npm init -y 或者 npm init --yes 极速创建 package.json

  • 包名不能使用中文、大写,默认值是:文件夹的名称 ,所以文件夹名称也不建议使用:中文和大写

NPM 搜索包

项目开发过程中我们为了快速完成某个任务,可以通过NPM提供的命令来寻找包,快速开发:

  • npm s 包类型npm serach 包类型 通过指定包类型,到NPM官网库中寻找匹配的包来进行开发

在这里插入图片描述

上述,通过控制命令查找包太不方便,实际开发过程中更多的是通过官网进行查找: npmjs.com

NPM 下载安装包

🆗,确认需要安装的包,开始进行下载使用了,NPM 常用下载命令: npm i 包名npm install 包名

运行之后文件夹下会增加两个资源: node_modules 文件夹 存放下载的包、package-lock.json 包的锁文件 用来锁定包的版本
在这里插入图片描述

使用uniq 数组工具包:

第三方包: 可以快速的满足程序的开发,uniq可以帮助我们快速操作数组:快速去重一组数组的重复元素;

index.js: 导入第三方uniq包实现快速数组去重开发效果;

//导入uniq第三方包:包下载之后和内置模块一样直接导入;
const uniq = require('uniq');
//使用uniq第三方包:快速实现数组去重;
let arr = [1,2,3,3,4,4,5,6,5,7,8,8];
let arr2 = uniq(arr);
console.log(arr2);                  //[1,2,3,4,5,6,7,8]

require 导入三方包基本流程: 向上原则

  • 在当前文件夹下 node_modules 中寻找同名的文件夹,

  • 没有继续:向上 node_modules 中寻找同名的文件夹,直至找到磁盘根目录,

  • 向上原则是为了建立清晰的层次结构、提高软件系统的模块化程度,有助于创造稳定、灵活、可维护和可扩展的软件设计;

NPM 安装包的依赖

生产|开发依赖包:

实际开发过程中为了方便稳定开发: 程序环境分为开发环境|生产环境

  • 开发环境: 是程序员专门用来写代码的环境,一般是指程序员的电脑,开发环境一般由开发者自己访问;
  • 生产环境: 是项目代码正式运行的环境,一般是指正式的服务器电脑,生产环境的项目每个客户都可以访问;

所以: 在开发过程中对依赖包也有分类,有些包仅在开发过程中使用,如果发布一起打包则会占用服务器性能效率;

我们可以在安装时设置选项来区分依赖的类型 ,目前分为两类:

  • 生产依赖安装(默认): npm i -S 包名npm i --save 包名 包信息保存在 package.json 中 dependencies 属性;
  • 开发依赖安装: npm i -D 包名npm i --save-dev 包名 包信息保存在 package.json 中 devDependencies 属性;
全局依赖包:

另外NPM除了安装开发依赖包: 还支持将包安装到全局环境中,可以在任何项目中使用,通常用于安装命令行工具;

不是所有的包都适合全局安装 , 只有全局类的工具才适合,可以通过查看包的官方文档来确定安装方式 ,这里先不必太纠结

  • npm install -g 包名 通过以下命令可以全局安装包,-g 选项表示全局安装;

示例: 以安装 nodemon(一个用于监视文件变化并自动重启 Node.js 应用程序的工具)为例:

在这里插入图片描述

  • 使用全局包nodemon 监听|启动node项目:项目文件更新自动重新启动!热部署!

注意事项:

  • 全局安装的包通常会被安装在系统的全局目录中:node安装目录下的 node_modules
  • 在某些系统上,可能需要使用管理员权限执行全局安装的命令(使用 sudo 或以管理员身份运行命令)
安装包依赖:

在项目协作中有一个常用的命令就是 npm i

通过该命令可以依据 package.jsonpackage-lock.json 的依赖声明安装项目依赖

  • 因为: 在多人协作开发过程中,项目可能会用到很多很多的包 而: 导致项目体积过大,不方便团队成员之间共享项目源代码;

  • 所以: 在实际开发过程中,不建议将node_modules文件夹 进行git管理,建议添加 .gitignore 忽略文件;

  • npm 提供了一个快捷命令:快速安装 package.json 管理的所有依赖包:npm install 或 npm i

  • 当我们拿到一个 剔除了 node_modules 的项目之后: 最长使用的命令

指定包版本:

项目中可能会遇到版本不匹配的情况,有时就需要安装指定版本的包,可以使用下面的命令的:

  • 命令格式: npm i 包名@版本号 实际情况可以先去官网确认版本存在,避免麻烦;
  • 命令示例: npm i jquery@1.11.2 下载安装指定的1.11.2版本的jquery包;
卸载依赖包:

项目中可能需要删除某些不需要的包,可以使用下面的命令

  • 局部删除: npm uninstall 包名npm remove 包名npm r 包名
  • 全局删除: npm uninstall -g 全局依赖包名npm remove -g 全局依赖包名

⚡注意⚡: 项目中执行删除命令,会把卸载的包自动从 package.jsondependencies 中移除掉 团队开发需协商操作;

定义执行脚本:

package.json:package.json 文件中,你可以通过 scripts 字段定义一些自定义脚本,以便在项目中执行特定的任务

{
  //... ...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "server": "node ./index.js",
    "start": "node ./index.js"
  },
 //... ...
}

自定义脚本可以通过 npm run script-name 的方式运行: 且自定义脚本也支持向上原则

  • 上述为例: npm run server 就相当于在执行:node ./index.js

  • start别名,使用时可以省略 run npm start 就相当于:node ./index.js

  • 用途:如果一个项目有多种环境配置,每次启动一堆参数: 定义脚本可以更快速方便启动|管理不同环境的项目;

CNPM | YNPM

CNPM

CNPM 全称为 China Node Package Manager

是一个淘宝构建的 npmjs.com 的完整镜像,也称为**『淘宝镜像🪞**

由于一些网络限制和访问速度的问题,国内开发者在使用 npm 安装 Node包时可能会遇到下载速度慢、甚至失败的情况

CNPM 通过在国内搭建了镜像服务,将 npm 的包镜像到国内服务器上,从而提高了包的下载速度,并减轻了对国际网络的依赖;

NPM 使用 CNPM

安装: 通过 npm 来安装使用:cnpm 全局服务工具;

npm install -g cnpm --registry=https://registry.npmmirror.com

从安装命令就可以知道,cnpm 其本质还是npm,所以其使用命令也和npm几乎异,本魔法师也不常用🧙‍♂️🪄 简单介绍:

#cnpm的命令几乎和npm一致多了一个c开头;

#初始化	cnpm init
#安装包	
	cnpm i 包名		# 默认部署
	cnpm i -S 包名	# 生产环境包
	cnpm i -D 包名	# 开发环境包
	cnpm i -g 包名	# 全局安装包
#构建项目依赖 cnpm i
NPM 配置淘宝镜像

对于习惯使用NPM 朋友,npm本身也支持修改包源来使用淘宝镜像:NPM管理镜像源有两种方式:

方式一:直接配置

npm config set registry https://registry.npmmirror.com/

方式二:使用nrm工具,配置管理npm镜像地址

  • 安装nrm: npm i -g nrm

  • 通过nrm 管理切换镜像地址: nrm use <源名>nrm ls 查看当前,可选源 星号代表当前使用源

      npm ---------- https://registry.npmjs.org/
      yarn --------- https://registry.yarnpkg.com/
      tencent ------ https://mirrors.cloud.tencent.com/npm/
      cnpm --------- https://r.cnpmjs.org/
    * taobao ------- https://registry.npmmirror.com/
      npmMirror ---- https://skimdb.npmjs.com/registry/
    
  • 添加源: nrm add <源名> <源地址> 示例: nrm add wsm https://wsm/

  • 删除源: nrm del <源名> 示例: nrm del wsm

YNPM

yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方地址

  • 超级安全:在执行代码之前,yarn 会通过算法校验每个安装包的完整性
  • 超级可靠:使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的 工作
  • 速度超快:yarn 缓存了每个下载过的包,所以再次使用时无需重复下载,且利用并行下载以最大 化资源利用率,因此安装速度更快

yarn 安装: npm i -g yarn 通过 npm 来安装使用:yarn全局服务工具;

yarn 常用命令: yarn的使用和npm 也相似,实际开发过程中下载速度块也有很多人使用…

# 初始化
	yarn init \ yarn init -y
# 安装包
	yarn add 包名				#生产依赖
	yarn add 包名 --dev		#开发依赖
	yarn global add 全局包名   #node全局依赖
# 删除包
	yarn remove 包名
    yarn global remove 全局包名
# 一键构建项目依赖
	yarn
# 运行命令别名<script>
	yarn <别名>		#和npm run <别名> 不同不需要加 run

yarn 注意事项: yarn全局包安装,并不会默认配置系统的全局变量所以会,产生安装识别的错觉:个人建议全局可以考虑npm

npm 和 yarn 选择

个人项目: 如果是个人项目, 哪个工具都可以 ,可以根据自己的喜好来选择

企业项目: 企业项目要根据项目代码来选择,可以通过锁文件判断项目的包管理工具,切记勿串用导致包管理异常!


ESM 模块化

在 ES6 之前,JavaScript 并没有原生支持模块化,因此开发者们使用一些第三方库或自己实现一些模块化方案:

或多或少存在一些问题: 命名冲突、依赖管理,单个对象导出,多次导出会覆盖之前的结果;

于是官方在 ES6 引入了 ESModule 模块化规范来解决这些问题:

  • ESModule 模块化规范是一种静态的模块化方案:
  • 它允许开发者将代码分割成小的、独立的模块,每个模块都有自己的作用域,ESModule 规范是基于文件的
  • ESModule 的模块解析规则是基于 URL 解析规则的:import 语句导入模块时,模块加载器会根据指定的路径解析出对应的 URL
  • 浏览器中: URL 解析规则是基于当前页面的 URL 进行解析,并将其作为唯一标识符来加载对应的模块文件;
  • **NodeJs 中:**URL 解析规则是基于当前运行脚本的路径进行解析;

ESM 初体验:

ESM是官方推行原生的模块化规范,很多浏览器皆支持,类似CommonJs的写法,通过设置type=module 用于HTML中,Node也逐渐开始支持; 语法如下:

  • 模块暴漏: exports 关键字,用于设置模块中要暴漏的属性|函数变量,可以暴露任意数据类型;
  • 模块导入: import 关键字,用于导入Xxx.JS文件地址,并获取其中暴漏的属性|函数变量;

moduleOne.JS: 分别暴露:分别在需要暴漏的属性|函数变量前加:export关键字声明;

export const name = 'wsm';
export function sayName() { return `我叫${name}`; }

index.HTML: 前端页面默认通过<scirpt type="module" >块进行接收,需设置类型则浏览器无法判断是模块导入报错;

导入语法: import * as 变量别名 from "./JS文件地址.Js";

  • import:模块导入的关键字、*:表示接收所有的.JS 文件暴漏变量、
  • as 变量别名:将暴漏的变量封装为一个新的变量别名、from "./文件地址.JS" 指定要导入JS模块的文件相对路径;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 指定scirpt块用于模块导入 -->
    <script type="module">
        // 通用import导入模块,获取|使用模块对象;
        import * as m1 from "./moduleOne.js";
        console.log(m1);
        console.log(m1.name);
        console.log(m1.sayName());
    </script>
</body>
</html>

启动工具: 即可在浏览器,开发者工具中查看console 查看输出内容;🆗 页面模块导入成功!

模块的暴漏:

ESM: 针对多种不同的应用场景,有多种模块暴漏方式:分别暴漏统一暴漏default默认暴漏 可能不同人不同叫法,总体如此;

/** 分别暴漏 */
export const name = 'wsm';
export function sayName() { return `我叫${name}`; } //分别在需要暴漏的属性|函数变量前加:`export`关键字声明;
/** 统一暴漏 */
const name = 'wsm';
function sayName() { return `我叫${name}`; }

export { name, sayName }    //在 暴漏.JS文件末尾通过: export{x,x,...} 批量管理暴漏的变量;
/** 默认暴漏: export default { 键:值形式属性|函数暴漏; } */
export default { name: 'wsm', sayName: function () { return `我叫${this.name}`; } }	//default相当于对象的封装所以需要this引用;

在这里插入图片描述
根据顺序对应三段module 的导入: ⚡⚡ 特殊的是: export defalut{ } 默认暴漏返回的是一个 default 对象;

模块的导入:

  • 常规导入: import * as 别名 from "文件地址.JS"
  • 默认暴漏简: import 别名 from "默认暴漏文件地址.JS"默认暴漏的.JS文件,支持的简介导入写法;
  • 解构赋值导入: import {模块匹配变量名, 模块匹配变量名 as 别名, ...} from "文件地址.JS" 对于多个模块导入可能存在同名变量,as 别名可以解决;
<script type="module">
    /** 常规导入方式: */
    import * as m1 from "./module01.js";
    import * as m2 from "./module02.js";
    import * as m3 from "./module03.js";
    console.log(m1);
    console.log(m2);
    console.log(m3);

    /** 解构赋值导入: 想对于*的全导入解构更具有选择性 */
    import { name, sayName } from "./module01.js";
    import { default as defaultobj } from "./module03.js";
    import { name as name2, sayName as sayName2 } from "./module02.js";
    console.log(sayName());
    console.log(sayName2());
    console.log(defaultobj.sayName());

    /** 默认暴漏(简介形式: 仅默认暴漏支持... */
    import defaultobj2 from "./module03.js";
    console.log(defaultobj2.sayName());
</script>

前端工程化:

ESM 项目结构:

🆗,上述了解了ESM 模块化的使用: 而对于一个项目所需要的模块非常多,实际开发中需要大量的代码来进行模块导入,而为了解决这个问题:

针对项目中大量的模块导入,为了方便管理: 通常配置一个入口.JS 进行批量导入|管理模块;

index.html 页面仅需要导入一个 mapp.JS 即可批量的导入所有的模块引用;

ESM 结合 NPM:

🆗,到这里已经基本掌握ESM模块化的基本流程: 但我们都知道ES6模块化技术,出现晚于很多模块化社区:

实际开发中经常二者结合使用,达到1+1>2 的效果,ESM可以结合NPM 强大的第三方模块社区库,更加方便快速完成代码开发:

解决ES版本兼容问题:
  • 我们都知道早期,互联网大战时代诞生了很多,JS浏览器环境,导致同一个代码,不同的浏览器可能展示效果不同;
  • 而,ES6新增的模块化技术,很多的浏览器版本短时间无法完全适配,导致很多麻烦😵经过一些列调用;
  • 最终解决方案:通过编译工具将ES6语法,翻译成ES5进行页面引用渲染 编译工具: babel
  • 同时ES6 支持 NPM可以更方便在项目中使用 Babel Babel官方🔗

1. NPM 初始化前端项目

2. NPM 安装需要的服务包工具: babel-cli 命令行工具babel-preset-env 预设翻译ECMA包browserify 前端打包工具

  • 使用:babel-cli+babel-preset-env 将原生翻译成了CommonJS模块化语法,浏览器不识别)、所以需用Browserify再次编译;
#切换项目根目录,npm 初始化
npm init -y

#NPM 安装翻译|打包工具:
#babel-cli 命令行工具、
#babel-preset-env 预设翻译ECMA包、browserify|webpack 浏览器打包工具本次使用browserify
npm i babel-cli babel-preset-env browserify -D  #NPM进行批量安装 -D 开发依赖; 下载的比较慢耐心等待;

#npm 使用babel+babel-preset-env进行翻译
#npx babel 源目录 -d 新目录 --presets=babel-preset-env
npx babel resource/JS -d dist/JS --presets=babel-preset-env
#resource/JS -d dist/JS 将原resource/JS目录ES6语法——转换——为dist/JS目录ES5语法;

#babel生成的仅是CommonJS模块化语法,并不支持浏览器直接使用,还需要browserify进行二次打包;
npx browserify dist/JS/mapp.js -o dist/main.js
# npx browserify 源主文件.JS -o 新主文件.JS

3. 前端页面引入:最终browserify 包管理工具生成的: main.js 主文件模块入口

<!-- 指定scirpt块用于模块导入 -->
<!-- <script src="./resource/JS/mapp.js" type="module"></script> -->
<script src="./dist/main.js" type="module"></script>    <!-- 页面引入翻译打包后的原生JS,避免版本导致渲染异常! -->
ESM 引入NPM包:

Demo: 使用 NPM 安装 Jquery包,并使用Jquery修改页面背景颜色;
在这里插入图片描述

resource/JS/mapp.js: 麻烦:前端工程化之后,代码更新也需要随之进行更新,才能看到实施效果… 后期框架解决了这个问题;

NPM 安装完包,在原生ES6中可以直接通过:import 别名 from "模块名"; 进行导入模块,参与项目快速开发;

//使用Jquery 修改页面背景颜色
import $ from 'jquery';     //相当于node中的 const $ = requrie('query');
$('body').css('background','pink');

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

n-皇后-dfs

import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Scanner;public class Main {static int n,N 20; //这里只会用到2 * n - 1的格子,开大点保险static char[][] g new c…

编曲学习:功能和声 歌曲结构 和弦编配(上)

34届三和弦 功能和声 歌曲结构 和弦编配&#xff08;上&#xff09;https://app8epdhy0u9502.pc.xiaoe-tech.com/live_pc/l_65b4e014e4b064a83b8f44fd?course_idcourse_2XLKtQnQx9GrQHac7OPmHD9tqbv 34届独立音乐人编曲训练营https://app8epdhy0u9502.pc.xiaoe-tech.com/p/t_…

【Java程序设计】【C00219】基于SSM的大学生课程管理系统(论文+PPT)

基于SSM的大学生课程管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这个一个基于SSM的大学生课程管理系统&#xff0c;本系统共分为三种权限&#xff1a;管理员、教师和学生 管理员&#xff1a;查看个人中心、学生管理、公告信…

CTF-WEB的知识体系

CTF概念 CTF是Capture The Flag的缩写&#xff0c;中文一般译作夺旗赛 CTF起源于1996年DEFCON全球黑客大会 DEFCONCTF是全球技术水平和影响力最高的CTF竞赛 竞赛模式 解题模式:解决网络安全技术挑战(即找到flag)&#xff0c;提交后获取相应分值。 攻防赛模式:要求找到其他队…

计算机基础知识讲解(原码反码补码)(以及在C语言里面是如何计算和运用的)

补码反码掩码以及原理 补码、反码和掩码是计算机科学中用于表示和处理数值的三种编码方式。 原码 原码是最直观的数值表示方法&#xff0c;它将数值的二进制表示与其符号位结合起来。在原码表示中&#xff0c;正数的符号位为0&#xff0c;而负数的符号位为1。原码的缺点在于…

Django实例_后台管理及分页器

原理步骤参考: Django开发_14_后台管理及分页器-CSDN博客 一、创建Django项目 二、创建page_app python manage.py startapp page_app三、修改settings.py文件 (一)添加app (二)设置每页显示数据个数 (三)设置中文显示 四、总路由添加子路由路径 from django.contrib impo…

MD5算法:高效安全的数据完整性保障

摘要&#xff1a;在数字世界中&#xff0c;确保数据完整性和安全性至关重要。消息摘要算法就是一种用于实现这一目标的常用技术。其中&#xff0c;Message Digest Algorithm 5&#xff08;MD5&#xff09;算法因其高效性和安全性而受到广泛关注。本文将详细介绍MD5算法的优缺点…

C++初阶:入门泛型编程(函数模板和类模板)

大致介绍了一下C/C内存管理、new与delete后&#xff1a;C初阶&#xff1a;C/C内存管理、new与delete详解 我们接下来终于进入了模版的学习了&#xff0c;今天就先来入门泛型编程 文章目录 1.泛型编程2.函数模版2.1概念2.2格式2.3函数模版的原理2.4函数模版的实例化2.4.1隐式实例…

leetcode 27.移除元素(python版)

需求 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度…

Cocos creator 动作系统

动作系统简介 是用于控制物体运动的一套系统&#xff0c;完全依赖代码进行实现&#xff0c;动态调节节点的移动。 移动 cc.moveTo 移动到某个坐标&#xff08;x,y&#xff09; //1秒时间内&#xff0c;移动到0,0let action1 cc.moveTo(1,0,0)this.node.runAction(action1)c…

LeetCode.2670. 找出不同元素数目差数组

题目 题目链接 分析 一种暴力的方法&#xff0c;枚举数组所有数字&#xff0c;分别计算当前元素前面不同的元素和后面不同的元素&#xff0c;然后相减即可。这样的话太暴力&#xff0c;前缀和后缀也需要分别遍历&#xff1a;O(N*2)了。 我们来优化一下&#xff1a; 根据这种…

Git 介绍 与 配置

Git 介绍 Git是一个分布式版本控制系统&#xff0c;用于跟踪文件的更改和协作开发。它可以管理项目的版本历史记录&#xff0c;并允许多个开发者在同一时间进行并行开发。 解决上图产生的问题就出现了git 分布式版本控制系统 看下图 Git 配置 Git的基本配置包括用户名和电子邮…

基于深度学习的鸟类识别系统matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 卷积神经网络基础 4.2 GoogLeNet模型 4.3 鸟类识别系统 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ............................…

使用Neo4j做技术血缘管理

目录 一、neo4j介绍 二、windows安装启动neo4j 2.1下载neo4j 2.2 解压文件 2.3 启动neo4j 三、neo4j基础操作 3.1 创建结点和关系 3.2 查询 3.3 更改 3.4 删除 四、技术血缘Demo实现 4.1 构建节点对象 4.2 构建存储对象 4.3 创建有属性关联关系 4.4 最后是图结果…

工业物联网接入网关在制造企业的实际应用-天拓四方

随着工业4.0和智能制造的兴起&#xff0c;工业物联网&#xff08;IIoT&#xff09;已成为工厂自动化的关键驱动力。在这个转变中&#xff0c;工业物联网网关扮演着至关重要的角色。它们充当了设备与企业系统之间的桥梁&#xff0c;实现了数据采集、分析和设备控制等功能。 案例…

微信开放平台第三方开发,实现代小程序认证申请

大家好&#xff0c;我是小悟 微信小程序认证整体流程总共分为五个环节&#xff1a;认证信息填写、平台初审、管理员验证、供应商审核和认证成功。 服务商可以代小程序发起认证申请。平台将对认证基础信息进行初步校验。通过后&#xff0c;平台将向管理员微信下发模板消息&…

实习日志8

1.捷通打印机 1.1.驱动问题&#xff08;不支持RFID设置&#xff09; 换一个驱动&#xff0c;报另一个错 找技术人员对接&#xff0c;换了个新驱动 查看端口 安装驱动&#xff08;选择USB002&#xff09; 1.2.rfid校验不准问题&#xff08;纸张有空白&#xff09; rfid未校验没…

数据库MySQL查询设计||给定四个关联表,其定义和数据加载如下:-- 学生表 Student-- 选课表 SC

SQL查询设计 给定四个关联表&#xff0c;其定义和数据加载如下&#xff1a; -- 学生表 Student create table Student(Sno varchar(6), Sname varchar(10), Sdate datetime, Ssex varchar(10)); insert into Student values(01 , 赵雷 , 1999-01-01 , 男); insert into St…

解决Could not transfer artifact org.springframework.boot的问题

进行maven更新的时候&#xff0c;发现报错了 Could not transfer artifact org.springframework.boot&#xff0c;提示网络错误&#xff0c;搜了一下&#xff0c;应该是要忽略https 在maven设置中添加如下语句 -Dmaven.wagon.http.ssl.insecuretrue -Dmaven.wagon.http.ssl.a…

微信投票小程序源码系统:无限多开,吸粉利器, 礼物道具,功能强大 带完整的安装代码包以及搭建教程

随着互联网的不断发展&#xff0c;社交媒体已成为人们生活中不可或缺的一部分。而微信作为中国最大的社交软件之一&#xff0c;拥有着庞大的用户群体和广泛的影响力。在这样的背景下&#xff0c;微信投票小程序应运而生。今天小编要向大家介绍的是一个功能强大的微信投票小程序…