//web.js
(function (root, factory) {
//判断define是否存在
if (typeof define === 'function' && define.amd) {
// 存在则使用AMD方式加载模块
define(['b'], factory);
} else {
// 不存在则使用浏览器全局变量暴露模块
root.web = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
从模块化谈起
近年来,js开发涌现出了诸多模块化解决方案,例如以在浏览器环境之外(服务端)构建
JavaScript
生态系统为目标而产生的CommonJS
规范,从CommonJS
社区中独立出来的AMD
规范(异步模块定义),还有国人制定的CMD
规范等。随着遵循AMD
规范的RequireJS
的流行,AMD
规范在前端界已被广泛认同。后来,随着npm社区的逐渐壮大,CommonJS
也越来越受欢迎,于是产生了统一这两种规范的需求,即希望提供一个前后端跨平台的解决方案,也因此产生了UMD
(通用模块定义)规范。CommonJS
定义的是模块的同步加载,主要用于Node端;而遵循AMD规范的RequireJS
则是异步加载,适用于浏览器端。requirejs
是一种在线”编译” 模块的方案,相当于在页面上加载一个AMD 解释器,以便于览器能够识别define、exports、module
,而这些东西就是用于模块化的关键。1.
CommonJS
同步式的require
Node端的模块加载遵循
CommonJS
规范,该规范的核心思想是允许模块通过require
方法来加载。该规范首先加载所要依赖的其他模块,然后通过
exports
或module.exports
来导出需要暴露的接口。但它的缺点也是显而易见的,即一个文件一个文件的加载很容易发生阻塞。2. 使你的模块兼容AMD规范
定义一个叫
web.js
的模块,依赖于另一个叫b
的模块。如果你不想支持浏览器全局路径,那么你可以移除root
并传递this
参数在函数顶部。3.
define.amd
属性为了清晰的标识全局函数(为浏览器加载script必须的)遵从AMD编程接口,任何全局函数应该有一个"amd"的属性,它的值为一个对象。
关于RequireJS的使用不在本文范围之内,因此不展开讲解,有兴趣的请移步我的另一篇文章:
AMD与异步加载
因为
CommonJS
阻塞式的缺点,所以并不适合前端。于是有了AMD异步加载模块的规范。Asynchronous Module Definition
规范其实只有一个主要接口define(id?, dependencies?, factory)
,它要在声明模块的时候指定所有的依赖dependencies
,并且还要当做形参传到factory
中,对于依赖的模块提前执行,依赖前置。因为浏览器端的需求和同步require的问题,所以社区引进了异步模块加载的规范,即AMD规范。
使你的模块兼容于UMD规范:
UMD规范实现的思路:
Node.js
模块格式,即exports
对象是否存在。AMD
方式加载Node
即global
,浏览器即window。例如,创建一个兼容UMD规范的jQuery插件:
CMD
Common Module Definition
规范和 AMD 很相似,尽量保持简单,并与CommonJS
和Node.js
的Modules
规范保持了很大的兼容性。CMD规范地址:https://github.com/seajs/seajs/issues/242
ES6 module
ECMAScript6
內建的用法:为什么只载入
JavaScript
文件?为什么模块化系统只帮助开发者处理
JavaScript
?然而还有其他静态资源需要被处理,比如:因为上面这些动机,所以有了
webpack
。webpack
webpack
是一款模块封装工具(module bundler,是打包工具,也是模块加载工具,各种资源都可以当成模块来处理),webpack
会将模块与其他相关联的模块,函数库,其他需要预编译的文件等整合,编译输出此模块的静态资源文件。module具有如下属性:
!
用于分隔loaders"include" 通常被用于匹配目录:
简单的说,webpack会把我们常用的
.less
,.scss
,.jade
,.jsx
等等文件编译成纯js + 图片
(图片有时也可以被编译成base64
格式的dataUrl
)。webpack的优势和特点:
webpack拥有更聪明的解析工具可以处理几乎所有的第三方函数库。甚至允许在相依性设定上使用表达式,例如:
require("./templates/" + name + ".jade")
,这几乎能处理大部分的模块化标准(CommonJS, AMD)。webpack常用命令
在项目中使用
webpack
首先在项目根目录新建一个
package.json
或者通过$ npm init
指令来产生:接着通过
npm
指令安装webpack
:单纯的编译指令
配置对象内容
context:用来指明entry选项的基础目录(绝对路径)。默认值为
process.cmd()
,即webpack.config.js
文件所在路径对象
entry
定义了打包后的入口文件,可以是数组(所有文件打包生成一个filename文件),对象或者字符串
该段代码最终会生成一个
page1.bundle.js
和page2.bundle.js
,并存放到./dist/js/page
文件夹下chunkFilename
是非主入口的文件名,当按需异步加载模块的时候,这时生成的文件名是以chunkname
配置的output
:该参数是个对象,定义了输出文件的位置及名字:path
: 打包文件存放的绝对路径publicPath
: 网站运行时的访问路径URLfilename
:打包后的文件名你可以使用
<name>=<filename>
的格式来替代entry point
建立一个別名:接着执行如下命令:
对象
output
表示欲输出的路径,其会被映射到设定档中的
output.path
以及output.filename
output.filename
:指定每一个在磁盘上输出的文件名,不允许指定绝对路径output.path
:输出绝对路径目录(必须)output.publicPath
:指定在浏览器端引用的文件公开URL地址对象
resolve
webpack在构建包的时候会按目录进行文件的查找,
resolve
属性中的extensions
数组可用于配置程序可以自行补全哪些文件后缀。extensions
第一个是空字符串,对应不需要后缀的情况。比如,为了查找CoffeeScript
文件,你的数组应当包含字符串".coffee"
。使用extensions
,在引入模块的时候就不需要写后缀,会自动补全resolve.alias
定义别名对象
externals
当我们想在项目中
require
一些其他的类库或者API
,而又不想让这些类库的源码被构建到运行时文件中, 这在实际开发中很有必要。此时我们就可以通过配置externals
参数来解决这个问题:这样我们就可以放心的在项目中使用这些API了:
配置项详情:https://webpack.github.io/docs/configuration.html
css样式和图片的加载
你可以在你的js文件里引入css文件和图片,例如:
当你
require
了CSS(less或者其他)文件,webpack
会在页面中插入一个内联的<style>
标签去引入样式。当你require
图片的时候,bundle文件会包含图片的url
,并通过require()
返回图片的url
。当然,你需要在
webpack.config.js
里做相应的配置:当然,你需要先通过npm包来安装这些loader,
webpack
会通过test
查找匹配文件,然后加载相应的loader
。比如通过npm安装sass loader
:实例一
新建一个
content.js
然后编辑
entry.js
加入require
打开浏览器,看到屏幕输出:
"It works from content.js";
Webpack 会给每个模块一个唯一的
ID
然后通过ID
存取这些模块,这些模块都会被整合到bundle.js
里面。webpack插件和使用方法介绍
1.
CommonsChunkPlugin
合并公共代码它用于提取多个入口文件的公共脚本部分,然后生成一个 公共文件来方便多页面之间进行复用。以下是该插件的使用方法和webpack的具体用法介绍:
Webpack
中将打包后的文件都称之为Chunk
。这个插件可以将多个打包后的资源中的公共部分打包成单独的文件。这里指定公共文件输出为common.js
Webpack
本身只能处理JavaScript
模块,如果要处理其他类型的文件,就需要使用loader
进行转换。 不同模块的加载是通过模块加载器(webpack-loader
)来统一管理的。!
用来定义loader
的串联关系,”-loader”
是可以省略不写的,多个loader
之间用“!”
连接起来,但所有的加载器都需要通过npm
来加载。2.
UglifyJsPlugin
压缩js文件3.
Extract Text Plugin
大家都知道在
webpack
中CSS
是可以被require()
的,webpack
会自动生成一个<style>
标签并加入到html
的<head>
标签 中。但是在发布时,我们可能只希望有一个被打包过后 css 文件。这时Extract Text Plugin
就能帮助我们完成这项任务。以上设置会输出一个
app.bundle.css
的文件。4.
html-webpack-plugin
webpack中生成HTML的插件。
详情:https://www.npmjs.com/package/html-webpack-plugin
5.
ProvidePlugin
ProvidePlugin
插件可以定义一个共用的插件入口,以后的文件就不需要require('react')
也能使用React了。6.
babel loader
Babel-loader
能够将JSX/ES6
文件转为js文件配置:
插件列表:http://webpack.github.io/docs/list-of-plugins.html
开发服务器安装
Webpack
开发服务器需要单独安装,同样是通过npm
进行:可以使用
webpack-dev-server
直接启动,也可以增加参数来获取更多的功能,具体配置可以参见官方文档。在终端输入:
然后打开:http://localhost:8080/webpack-dev-server/index.html
在
webpack.config.js
里配置:详情:https://webpack.github.io/docs/webpack-dev-server.html
使用
browser-sync
实时刷新页面如果每次更改代码都要重新执行
webpack
命令不免太过麻烦,所以这里推荐使用browser-sync-webpack-plugin
,可以监听代码变化,实时刷新页面。安装
browser-sync-webpack-plugin
:webpack.config.js
配置:实例二:
react+webpack+es6
开发模式从我之前的博客移过来的:http://hawx1993.github.io/2016/03/21/webpack-development/