前端模块化

1
2
3
4
5
6
7
function func1(){
//...
}

function func2(){
//...
}

上述的func1func2函数分别形成了两个模块,需要使用的时候直接调用即可,但是这样无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系,再之后便有使用对象作为模块,将成员的都放置于对象中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1.js,定义变量、函数等
var a = 1;
var b = function(){
console.log(a);
}

// 导出方法,类似对象定义
module.exports = {
a: a,
b: b
}

/*
// 当导出的模块名与被导出的成员或方法重名时可以有如下写法
module.exports = {
a,
b
}
*/
1
2
3
4
5
6
// 2.js  导入方式一
const m1 = require("./1.js")

console.log(m1.a); // 1
m1.b(); // 1

require是依赖于node环境的,浏览器无法解析require,所以CommonJS是Node服务端的规范,我们将学一下ES6模块化

ES6在语言标准的层面上实现了模块的功能,是为了成为浏览器和服务器通用的模块解决方案,ES6标准使用exportexport default来导出模块,使用import导入模块

导出方式两种exportexport default

  • export 能按需导入,export default 不行
  • export 可以有多个,export default 仅有一个
  • export能直接导出变量表达式,export default不行。
  • export方式导出,在导入时要加{}export default则不需要。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 导出单个特性
// 在js定义变量、
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}

// 导出列表
export { name1, name2, …, nameN };

// 重命名导出,引用的时候是newname1,newname2
export { name1 as newname1, name2 as newname2 , …, nameN };

// 默认导出
export default expression;
export default function () { … } // also class, function*
export default function name1() { … } // also class, function*
export { name1 as default, … };

// 导出模块合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;
1
2
3
4
5
6
7
8
9
import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name"; // 将运行模块中的全局代码, 但实际上不导入任何值。
1
2
3
4
5
6
7
8
9
//常用的导出方式
export {
a,
b,
c
}

//导入方式
import {a,b,c} from './a.js'
1
2
<script src="./a.js" type="module" charset="utf-8"></script>
<script src="./b.js" type="module" charset="utf-8"></script>

匿名闭包,解决了命名冲突问题,但是出现了代码不可复用性

1
2
3
4
5
6
7
;(function(){
var name= '小明'
var age = 18
function sum(n1,n2){
return n1+n2
}
})()

通过obj对象导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//1.js文件
;var module = (function(){
var obj={}

var name= '小明'
var age = 18
function sum(n1,n2){
return n1+n2
}

obj.name = name;
obj.age = age;
obj.sum = sum;

})()

//-----------------------------------------------------------------------------------------------


//2.js文件,引用1.js导出的obj
;(function(){
console.log(moduleA.name) // logs 小明
console.log(moduleA.age) // logs 18
console.log(moduleA.sum(150,35)) //logs 185
})()

早期模块化开发都是通过闭包的方式避免命名冲突,通过对象导出。规模每一个人使用的模块命名

起步

webpack 用于编译 JavaScript 模块。一旦完成 安装,你就可以通过 webpack CLIAPI 与其配合交互。如果你还不熟悉 webpack,请阅读 核心概念对比,了解为什么要使用 webpack,而不是社区中的其他工具。

前提条件

在开始之前,请确保安装了 Node.js 的最新版本。使用 Node.js 最新的长期支持版本(LTS - Long Term Support),是理想的起步。 使用旧版本,你可能遇到各种问题,因为它们可能缺少 webpack 功能, 或者缺少相关 package。

1
2
3
npm install --save-dev webpack
# 或指定版本
npm install --save-dev webpack@<version>

是否使用 --save-dev 取决于你的应用场景。假设你仅使用 webpack 进行构建操作,那么建议你在安装时使用 --save-dev 选项,因为可能你不需要在生产环境上使用 webpack。如果需要应用于生产环境,请忽略 --save-dev 选项。

1
npm install --global webpack

不推荐 全局安装 webpack。这会将你项目中的 webpack 锁定到指定版本,并且在使用不同的 webpack 版本的项目中, 可能会导致构建失败。

我在学vue的时候,是先安装全局的webpack,便于我在任何地方使用,也许以后开发项目,不能这样安装


学习webpack工具