优雅代码管理

模块化:更优雅的代码管理
// rollup.config.js
// file 打成单文件 dir 打成 chunk
module.exports = {
	input: './src/index.js',
	output: [
		{
			//dir: './dist/cjs',
			file: './dist/index-cjs.js',
			format: 'cjs'
		},
		{
			//dir: './dist/amd',
			file: './dist/index-amd.js',
			format: 'amd'
		},
		{
			//dir: './dist/esm',
			file: './dist/index-esm.js',
			format: 'esm'
		},
		// iife 和 umd 不支持 spliting  为什么不支持?
		{
			//dir: './dist/iife',
			file: './dist/index-iife.js',
			format: 'iife'
		},
		{
			//dir: './dist/umd',
			file: './dist/index-umd.js',
			format: 'umd',
			name: 'res'
		}
	]
}
// index.js
// 打成单文件的引入
import { safeGet } from './a.js'
safeGet({}, 'a.b.c')

// 打成多文件的引入
import('./a.js').then(({default: d}) => {
	console.log(d)
})
// a.js
import { get } from 'lodash'

export const safeGet = (target, path, defaultValue) => {
	return get(target, path, defaultValue) || defaultValue
}
AMD
define(模块名字?, [依赖], factory)  // factory 模块自己的逻辑

define('foo', ['utils', 'bar'], function (utils, bar) {
	utils.add(1, 2)
	return { name: 'foo' }
})
直接配置依赖路径
RequestJs.config({ paths: {
	'jquery': 'jquery CDN 地址'
}})

// 配置后使用
RequestJs(['jquery'], function (jquery) {
	//....
})
加载模块
RequestJs(['moduleA'], function (moduleA) {})
定义模块
RequestJs(['moduleA'], [], function () {
	return 'hello'
})
行为
define('a', function () {
	console.log('a load')
	return {
		run: function () { console.log('a run') }
	}
})


define('b', function () {
	console.log('b load')
	return {
		run: function () { console.log('b run') }
	}
})


require(['a', 'b'], function (a, b) {
	console.log('main run')
	a.run()
	b.run()
})


// a load
// b load
// main run
// a run
// b run
结论

require的时候加载了依赖的模块

AMD mini 实现
const def = new Map()
const defaultOptions = {
	path: ''
}

// from CDN  加载CDN文件
const _import = (url) => {
	return new Promise((resolve, reject) => {
		System.import(uel).then(resolve, reject)
	})
}

// normal script  加载其他文件
const _load = (url) => {
	return new Promise((resolve, reject) => {
		const head = document.getElementByTagName('head')[0]
		const node = document.createElement('script')
		node.type = 'text/javascript'
		node.src = url
		node.async = true
		node.onload = resolve
		node.onerror = reject
		head.appendChild(node)
	})
}

// 为什么不写 let const var? 通过这种方式 直接挂到全局(window)
rj = {}
rj.config = (options) => Object.assign(defaultOptions, options)

// 定义模块  触发是在 require 的时候  define 只是存
define = (name, deps, factory) => {
	// todo 参数判断 (省略)
	def.set(name, {name, deps, factory})
}

const _getUrl = (dep) => {
	const p = location.pathname
	return p.splie(0, p.lastIndexOf('/')) + '/' + dep + '.js'
}

// 触发加载依赖的地方
require = (deps, factory) => {
	return new Promise((resolve, reject) => {
		Promise.all(deps.map(dep => {
			// 走 CDN
			if (defaultOptions.paths[dep]) return _import(defaultOptions.paths[dep])
			// 其他
			return _load(_getUrl(dep)).then(() => {
				const {deps, factory} = def.get(dep)
				// 没有依赖
				if (deps.length === 0) { return factory(null) }
				// 有依赖
				return require(deps, factory)
			})
		})).then(resolve, reject)
	})
	.then(instances => factory(...instances))
}
CMD
// sea.js
define('a', function (require, exports, module) {
	console.log('a load')
	exports.run = function () { console.log('a run') }
})

define('b', function (require, exports, module) {
	console.log('b load')
	exports.run = function () { console.log('b run') }
})

define('main', function (require, exports, module) {
	console.log('main run')
	let a = require('a')
	a.run()
	let b = require('b')
	b.run()
})

seajs.use('main')

// main run
// a load
// a run 
// b load
// b run
CMD mini 实现
const modules = {}
const exports = {}
sj = {}

const _getUrl = (dep) => {
	const p = location.pathname
	return p.splie(0, p.lastIndexOf('/')) + '/' + dep + '.js'
}

const getDepsFromFn = (fn) => {
	let matches = []
	// 1、(?:require\()  ——>  require(  ——>  (?:) 非捕获性分组
	// 2、(?:['"])  ——>  require('
	// 3、([^'"]+)  ——>   a   ——> 避免回溯
	let reg = /(?:require\()(?:['"])([^'"]+)/g
	let r = null
	while((r = res.exec(fn.toString())) !== null) {
		res.lastIndex
		matches.push(r[1])
	}
	return matches
}

// script 标签加载模块
const _load = (url) => {
	return new Promise((resolve, reject) => {
		const head = document.getElementByTagName('head')[0]
		const node = document.createElement('script')
		node.type = 'text/javascript'
		node.src = url
		node.async = true
		node.onload = resolve
		node.onerror = reject
		head.appendChild(node)
	})
}

// 提取依赖  正则表达式   状态机
define (id, factory) => {
	const url = _getUrl(id)
	const deps = getDepsFromFn(factory)
	if (!modules[id]) {
		modules[id] = {url, id, factory}
	}
}

const _module = this
const _exports = (id) => exports[id] || (exports[id] = {})
// 这加载模块
const _require = (id) => {
	return _load(_getUrl(id)).then(() => {
		// 加载之后
		const {factory, deps} = modules[id]
		if (!deps || deps.length === 0) {
			factory(_require, _exports(id), _module)
			return _exports(id)
		}
		return sj.use(deps, factory)
	})
}

sj.use = (mods, callback) => {
	mods = Array.isArray(mods) ? mods : [mods]
	return new Promise((resolve, reject) => {
		Promise.all(mods.map(mod => {
			return _load(_getUrl(mod)).then(() => {
				const {factory} = modules[mod]
				return factory(_require, _exports(mod), _module)
			})
		})).then(resolve, reject)
	}).then(instances => callback && callback(...instances))
}

CommonJS

文件是一个模块,私有。内置两个变量 module require (exports = module.exports)
一个引入一个导出,就构成了通信的基本结构

缓存,require 会缓存一下
// a.js
var name = 'morrain'
var age = 18
exports.name = name
exports.getAge = function(){
    return age
}
// b.js
var a = require('a.js')
console.log(a.name) // 'morrain'
a.name = 'rename'
var b = require('a.js')
console.log(b.name) // 'rename'
引用拷贝还是值拷贝的问题(CMJ 是值拷贝)
// a.js
var name = 'morrain'
var age = 18
exports.name = name
exports.age = age
exports.setAge = function(a){
    age = a
}
// b.js
var a = require('a.js')
console.log(a.age) // 18
a.setAge(19)
console.log(a.age) // 18
CMJ mini 实现
const cache = {}

(function(modules) {
  const require = (mn) => {
    if (cache[mn]) return cache[mn].exports;
    let module = cache[mn] = {
      name: mn,
      exports: {}
    }

    modules[mn](module, exports, require)

    return module.exports
  }

  return require('index.js')

})({
  'a.js': function(module, exports, require) {
     // ...
  }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值