模块化开发
模块化发展
第一阶段
基于文件的划分模块方式
-
污染全局作用域
-
命名冲突问题
-
无法管理模块依赖关系
第二阶段
命名空间方式,每个模块只暴露一个全局对象, 所以模块成员都挂载在这个对象中
- 没有私有空间,在外部仍然会被访问到
第三阶段
立即执行函数,闭包方式,实现了私有成员的概念
模块规范化的出现
模块化标准+模块加载器
Commonjs模块,一个文件就是一个模块,每个模块都有单独作用域,通过module.exports导出成员,require函数中载入模块
AMD模块化,require.JS方法来进行规范化
CMD模块化,淘宝推出的一款类似于common.js的模块,以减少学习量
一般来讲,子啊Node.js中遵循CommonJS规范,在浏览器中遵循ES Modules规范
ES Modules
特性
通过给script添加type=module属性,就可以以ESModule的标准执行其中的JS代码
1、ESM自动采用严格模式,忽略use strict
2、每个ES Module中的变量都是运行在私有作用域中的
3、ESM是通过CORS的方法请求外部JS模块的,并且会延迟脚本的执行类似于defer属性
导出
通过export { }对外暴露接口
export class Person{}
export{ name,hello,Person}
// 也可以进行重命名
export{ name as fooname }
导入
通过import{ }引入外部的接口
路径:必须完整的文件名称、文件前面的/是不可以被省略的、也可以通过完整路径或者url
参数:如果我们忽略参数的传入,那么我们得到的只是这个模块,不会对外暴露变量;*表示导入所有的到处成员,as可以将所有变量存放在对象中,打点调用具体使用的变量
import * as mod from './module.js'
console.log(mod)
动态加载模块,通过异步加载之后再对其中的内容进行操作
import('./module.js').then(function (module) { console.log(module) })
提取默认成员的两种方法,一种是通过as进行重命名,或者逗号左边进行输出
import{name,age,default as title}from './module.js'
import title,{name,age}from './module.js'
console.log{name.age,title}
可以通过export直接将先一步import的内容直接暴露出去,在最终使用的地方直接import中间桥梁文件
导入导出注意
1、export{ 需要导出的值 } 是一个规定的写法,如果定义变量和对象中的成员一样,那么我们需用通过export default{ }进行导出
2、我们外部引入接口获得到的是一个变量存放的地址,并不是直接将变量赋值一份
3、在外部调用过程中,我们不能进行变量值的更改
浏览器Polyfill
一般来说不建议做法是引入外部解决兼容的JS文件,并且通过nomodule属性可以让识别ESMode的不去执行,只有不识别ESModule的浏览器采取加载该脚本
在node环境中如果我们想要使用ESModule,需要将所有的后缀名更改为.mjs,并在命令行中输入
node --experimental-modules index.mjs
可以导入原生模块,通过提取来提取模块内置成员,或者进行默认成员的导出
与Common.JS
ES Module中可以导入CommonJS模块,但是不能直接提取成员,始终只会导出一个默认成员,不是解构导出对象。CommonJS中不能导入ESModule模块,ESM中没有CommonJS中那些模块全局成员
import{ fileURLToPath } from 'url'
import{ dirname } from 'path'
__filename=fileURLToPath(import.meta.url)
__direname=dirname(__filename)
如果单独添加了package.json中引入type:”module“,那么就不需要修改后缀名为mjs。如果想要在ESM下执行CommonJS代码,就需要将CommonJS 的后缀名修改为.cjs
BABEL是JS编译器,可以让我们的新属性的JS转化为浏览器所支持的JS代码内容
webpack打包
ESModule存在环境兼容问题
模块文件过多,网络请求频繁
在开发阶段使用模块来书写,生产阶段则使用整体进行,并且需要支持多格式
由来概述
针对前端所用到的所有代码都可以进行模块化打包
使用
yarn init --yes //初始化项目
yarn add webpack webpack-cli --dev //安装包依赖
配置文件
默认打包路径是’src/index.js’—>‘dist/main.js’ //路径打包,我们可以单独创建一个webpack.config.js文件,node环境中配置转换的默认属性
const path=require('path')
//node环境下可以通过commonjs方法进行内置模块引入
module.exports={
entry:'./src/main.js',//获取源文件地址
output:{
filename:'buile.js', //打包后的命名
path:path.join(__dirname,'output')
//打包后的文件目录,必须使用绝对路径
}
}
在打包文件的过程中,会默认添加一些打包的样式,如果我们不想让代码压缩,就可以使用yarn webpack --mode development,mode后选项不同,则打包的方式就不同
单步调试
入口模块开始,获取到的是两个模块对应函数
加载require函数
调用模块函数、require函数、导出成员函数
表明是一个ESModule模块处理函数
header模块导出,append到body中
资源加载模块
Loader是Webpack的核心特性,借助于Loader就可以加载任何类型的资源,CSS加载案例
//加载我们转换需要的loader
yarn add css-loader --dev
//针对于其他加载模块我们所需要的规定
module: {
rules:[{ test:/.css$/,
//先去执行最后一个loader
use:['style-loader','css-loader' }]}
//把css转化的追加到页面上
yarn add css-loader --dev
//如果css样式是类选择,我们需要JS代码引入时添加一个类名
element.classList.add('heading')//添加类名
可以直接在JS代码中import引入我们想加载的其他模块,这样就可以只去考虑JS代码加载
学习新事物,我们需要的不是知道它具体怎么使用,这只是一部分,最主要的的是了解新事物的思想才是突破点
常用加载器
编译转换类——css.loader
文件操作类——file.loader
代码检查类——eslint.loader
加载方式
遵循ESModules标准的import声明,遵循CommonJS标准的require声明,遵循AMD的define函数和require函数,样式代码中的@import指令和url函数,HTML代码中图片标签的src属性
工作原理
Loader负责资源文件从输入到输出的转换,管道的概念,可以一次使用多个Loader
webpack插件
clean-webpack-plugin插件可以帮助我们每次加载前删掉之前加载的文件
html-webpack-plugin插件是来帮助我们生成html自定义名称等内容模板属性,如果需要生成多了html文件,那么就添加多个HtmlWebpackPlugin实例对象即可
copy-webpack-plugin插件用来拷贝复制其他类型文件
插件相比于Loader,拥有更宽的能力范围,通过钩子机制实现,类似于事件,在每一个过程都隐含了钩子,我们只需要直接在上面挂载不同任务的插件(一个函数或者是一个包含apply方法的对象)
插件就是通过在生命周期的钩子中挂载函数实现扩展
增强开发体验
http-server直接运行于浏览器
同时打开两个终端,一个运行–watch监听,一个通过browser-sync运行浏览器更新
实时更新修改
–watch监听文件变化,自动重新打包
source精准定位报错位置
Webpack Dev Server提供用于开发的HTTP Server,集成自动编译和自动刷新浏览器
yarn add webpack-dev-server --dev
暂存在内存中,减少磁盘的读写操作,提高效率
contentBase可以额外为开发服务器指定查找资源目录
devServer:{ contentBase:'./public '}
可以实现跨域解决方案:经过中间的开发服务器进行API请求代理;Source Map解决了源代码与运行代码不一致产生的问题
添加devtool:'source-map'可以帮助我们查看
不同的devtool有不同的效果区别
eval—是否使用eval执行模块代码,cheap-Source Map是否包含行信息,module—是否能够得到Loader处理之前的源代码
HMR模块热更行
在一个正在运行的机器上随时插拔设备,应用运行过程中实时替换某个模块,应用运行状态不受改变。
devServer:{ hot:true}
环境生产优化
生产环境注重运行效率,开发环境注重开发效率
根据环境不同导出不同配置(大项目),一个环境对应一个(中小型项目)
DefinePlugin的API_BASE_URL:可以帮助我们针对不同环境选择不同的环境配置选项
模块介绍
Tree Shaking
在生产模式下将不用的代码进行删除,usedExports负责标记空树叶,minimize负责摇掉空树叶
sideEffects
一般用于标记npm包标记是否有副作用,除了打包文件为还做了其他事情,没有副作用就可以直接删掉
代码分割
Code Slitting将模块通过我们设置的规则来打包成不同功能的包
多入口打包
一个文件一个打包入口,公共部分单独提取
动态打包
需要某个模块时,再去加载这个模块,都会进行被自动分包,不会存在浪费的情况
Mini-Css-Extract-Plugin自动打包css样式文件
Optimize-Css-Assets-Webpack-Plugin以压缩的方式输出
ize负责摇掉空树叶
sideEffects
一般用于标记npm包标记是否有副作用,除了打包文件为还做了其他事情,没有副作用就可以直接删掉
代码分割
Code Slitting将模块通过我们设置的规则来打包成不同功能的包
多入口打包
一个文件一个打包入口,公共部分单独提取
动态打包
需要某个模块时,再去加载这个模块,都会进行被自动分包,不会存在浪费的情况
Mini-Css-Extract-Plugin自动打包css样式文件
Optimize-Css-Assets-Webpack-Plugin以压缩的方式输出