这一次咱们谈谈模块问题。javascript
一般咱们但愿这个项目能够分为多个独立的模块,好比,上一次提升的 hello 函数,若是咱们定义为一个模块,其它模块引用以后,直接调用就行了。在前端怎么使用模块呢?这可说来话长了。html
若是咱们把 hello 函数定义在文件 hello.js 中,内容以下:前端
function hello(){ alert("Hello, Webpack!"); }
而后把主入口函数 index.js 的内容写成下面的内容,你应该会获得一个错误信息。java
require("./hello");
hello();
对话框是弹不出来的。错误信息以下:node
Uncaught ReferenceError: hello is not defined, 明明定义了 hello 函数,却恰恰说找不到。webpack
CommonJs 是目前比较流行,也是出现较早的模块技术,它诞生于 NodeJs,使用起来其实比较简单。web
首先,它把一个独立的文件当作一个模块,好比上面的 hello.js 文件,就能够当成一个模块。模块的名称就是文件名称,可是能够不用提供扩展名 .js,直接使用文件名就能够。typescript
在导入一个模块的时候,使用 require 函数,注意是函数,并非关键字,JavaScript 并无提供这个关键字。函数的参数就是模块名称,不过,要注意模块分为两种,自定义的模块和系统模块。npm
自定义的模块必须使用 . 或者 .. 开头的相对路径,若是都在同一个目录下,也须要使用 . 来表示当前路径,好比上面用到的 require("./hello")。json
不是使用 . 或者 .. 开始的相对路径的,都称为系统模块,系统模块的路径其实在 node_modules 文件夹中,每一个子文件夹就是一个系统模块。
require 函数的返回结果就是模块导出的内容。
咱们的模块没有导出任何内容。因此,虽然被 index 引用了,可是在 index 中倒是没法访问的。这也说明模块中定义的函数实际上是局部函数,并非一般意义上的全局函数了。
咱们要在模块中导出内容怎么办呢,CommonJs 提供了 exports 对象。
在 CommonJs 模块中,但愿导出的内容必须经过 exports 对象,这是 CommonJs 系统提供的系统对象,咱们能够直接使用。导出的内容以键值对的形式定义到这个对象上,键就是导出的名称,值就是准备导出的内容。
好比,咱们但愿将 hello 函数导出为名为函数的函数,好像挺绕的,其实很简单。
function hello(){ alert("Hello, Webpack!"); } exports.hello = hello;
将 index.js 函数的定义修改成
var hello = require("./hello").hello; hello();
从新执行 webpack 命令,刷新网页,你会看到函数执行了。
另一个著名的模块系统称为 AMD 模块,全称为 Asynchromous Module Defination,翻译过来就是异步模块规范,它是由 RequireJs 推进的。
首先,一个文件也被看做一个模块,因此,咱们还拿 hello.js 做为一个模块吧。
其次,定义模块使用 define 函数,函数的第一个参数是当前模块依赖的模块数组,若是没有依赖的函数,可使用一个空的数组表示。
define([], function(){ return { hello: function(){ alert("Hello, Webpack!"); } }; });
第二个参数就是模块的定义函数,这个函数的返回内容就是模块的导出内容。咱们这里导出一个对象包含咱们定义的函数的对象。
最后,咱们修改一下 index.js 来导入定义好的 AMD 模块,并调用 hello 函数。
define(['./hello'], function( helloModule ){ helloModule.hello(); })
此次,咱们的 index 依赖提早定义好的 hello 模块,注意模块命名的方式仍是注意自定义模块和系统模块的区别,在第二个函数参数中,它的参数就是被依赖模块导出的内容,因此这里的 helloModule 就是一个对象,它的 hello 属性就是咱们定义好的函数。
在 ES2015 中,定义了关键字,注意是关键字,不是函数了,模块导出的关键字是 export , 导入就是 import 了。
因此,hello 函数能够这样定义了。
export default function() { alert("Hello, Webpack!"); };
而 index.js 就能够这样定义。
import hello from "./hello";
hello();
可是,须要注意的是,你必须有 ES2015 的运行环境才行,目前不少浏览器不支持怎么办呢?
咱们能够将 ES2015 的代码先翻译成标准的 JavaScript 代码,就能够执行了。
而 TypeScript 做为 ES2015 的超集,咱们就使用 TypeScript 来实现。
首先,你必须确认你已经安装了 TypeScript 的编译器,全局安装 TypeScript
npm -g install typescript
安装以后,能够执行 tsc -v 来检查版本,目前最新是 2.0.3 版本。
将 hello.js 从新更名为 hello.ts,将 index.js 更名为 index.ts. ts 是 TypeScript 文件的扩展名。
你能够手工执行命令 tsc 分别将两个 typescript 文件编译为 javascript 文件。
生成的 hello.js
"use strict"; function default_1() { alert("Hello, Webpack!"); } exports.__esModule = true; exports["default"] = default_1; ;
生成的 index.js
"use strict"; var hello_1 = require("./hello"); hello_1["default"]();
而后,再次执行 webpack 从新打包,你会发现结果仍然正常执行。
在第三步,咱们能够手工使用 tsc 将 TypeScript 代码编译为 JavaScript 代码以后进行打包,可是这样太麻烦了,使用 ts-loader 咱们可让 webpack 自动先调用 tsc 将 TypeScript 代码编译为 JavaScript 代码,而后再自动进行打包工做。
首先,固然要安装 ts-loader 插件了。
npm install ts-loader --save-dev
目前是 0.9.5 版本。
为了在项目中使用 typescript,你还须要本地安装 typescript 一次。
npm install typescript --save-dev
还须要配置一下 TypeScript 如何编译代码。在当前目录中建立名为 tsconfig.json 的配置文件。
{ "compilerOptions": { "target": "es5", "sourceMap": true }, "exclude": [ "node_modules" ] }
这里的配置是说,但愿生成 es5 标准的 JavaScript 目标文件。
而后,配置 webpack 使用 ts-loader
var HtmlwebpackPlugin = require('html-webpack-plugin'); module.exports = { // 入口 entry: "./index.ts", // 输出的文件名 output: { filename: 'bundle.js' }, resolve: { // Add `.ts` and `.tsx` as a resolvable extension. extensions: ['', '.ts', '.js'] }, // 添加咱们的插件 会自动生成一个html文件 plugins: [ new HtmlwebpackPlugin({ title: 'Hello Webpack' }) ], module: { loaders: [ // all files with a `.ts` extension will be handled by `ts-loader` { test: /\.ts$/, loader: 'ts-loader' } ] } };
这里增长了两个内容,一个是 resolve 配置,这样咱们只须要使用模块名称,webpack 会自动添加后缀来查找模块文件。另外一个就是 module 中的 loader 了,这里是说遇到了 .ts 扩展名的文件,须要先使用 ts-loader 处理以后再打包。
如今,从新执行 webpack 命令,你会发现一切都已经处理好了,刷新页面,你应该看到代码正确执行了。
webpack 能够直接支持 CommonJs 和 AMD 模块,对于 TypeScript ,咱们还须要安装 TypeScript 和 ts-loader.
须要注意的是 Angular 2 使用 TypeScript 做为主力语言,你能作到这里,离 Angular 2 已经很近了。