我之前在 《前端搭环境之从入门到放弃》这篇文章中吐槽过,webpack中可以写commonjs格式的require同步语法,可以写AMD格式的require回调语法,还有一个require.ensure,以及webpack自己定义的require.include,再加上ES6的import语法,这么多岂不是会把人给搞乱。本篇就来梳理一下这些require各自的特点,以及都在什么场景下使用。

commonjs同步语法

经典的commonjs同步语法如下:

var a = require('./a');
a.show();

此时webpack会将a.js打包进引用它的文件中。这是最普遍的情形,不必赘述。

commonjs异步加载

在commonjs中有一个Modules/Async/A规范,里面定义了require.ensure语法。webpack实现了它,作用是可以在打包的时候进行代码分片,并异步加载分片后的代码。用法如下:

require.ensure([], function(require){
var list = require('./list');
list.show();
});

此时list.js会被打包成一个单独的chunk文件,大概长这样:

1.fb874860b35831bc96a8.js

可读性比较差。我在上一篇结尾也提到了,给它命名的方式,那就是给require.ensure传递第三个参数,如:

require.ensure([], function(require){
var list = require('./list');
list.show();
}, 'list');

这样就能得到你想要的文件名称:

list.fb874860b35831bc96a8.js

你也可以传入像"question/list"这样带层级的名字,这样webpack会按照层级给你创建文件夹。

需要注意的是,如果你在require.ensure的函数中引用了两个以上的模块,webpack会把它们打包在一起,比如:

require.ensure([], function(require){
var list = require('./list');
list.show();
var edit = require('./edit');
edit.display();
}, 'list_and_edit');

list.js和edit.js将会被打包成一个文件,并命名为list_and_edit.js。这就需要根据你的实际情况来衡量了,如果你不希望打包在一起,只能写两个require.ensure分别引用这两个文件。

多说一句,这种思维其实我是很不喜欢的,在编码阶段却要对打包的事情做出决策,明显违背了职责分离原则。

commonjs预加载懒执行

在上面的用法中,我们给require.ensure的第一个参数传了空数组,实际上这里是可以接收模块名称的,作用就是实现预加载懒执行。用法如下:

require.ensure(['./list'], function(require){
var list = require('./list');
list.show();
});

给require.ensure的第一个参数传了['./list'],执行到这里的时候list.js会被浏览器下载下来,但是并不会执行list.js模块中的代码,也就是webpack官网说的,不会进行evaluate。真正进行evaluate的时候是到了后面这句var list = require('./list');这就是所谓的懒执行。

写在函数中的多个模块会被打包在一起,这一点和上面没有区别。另外,写在数组中的模块也会跟他们打包在一起,不管你有没有手动执行。

这种写法也是有点别扭的,像是commonjs和AMD的结合体,而且一个模块名称还要写两次,真是不够优雅。所以webpack自己定义了一个方法,能够实现预加载。

webpack自带的require.include

require.include是webpack自己提供的,并没有什么规范做后台,所以是个小角色。它可以实现上面是预加载功能,而不用把模块写在数组中,用法如下:

require.ensure([], function(require){
require.include('./list');//此处只加载不执行
});

据webpack官网文档介绍,require.include还有一个作用是能把子模块中的公共部分,提取到父模块中,比如child1和child2都引用了list.js这个模块,那么如果在parent中include了list.js,那么子模块中的就会被删掉,相当于提升到了父模块中。(这里所谓的父子关系是指引用关系)

这个方法官方也是一笔带过,看来也是一个鸡肋的东西,用处不大。因为我发现require.include的返回值是undefined,也就是说,如果你想使用模块,姿势是这样的:

require.ensure([], function(require){
require.include('./preview'); //加载
let p = require('./preview'); //执行
p.getUrl(); //使用
}, 'pre');

AMD异步加载

webpack既支持commonjs规范也支持AMD规范,这就意味着AMD的经典语法是可以正常使用的,如:

require(['./list'], function(list){
list.show();
});

当然,这样写的话list.js也是被单独打包成一个文件的。与上面类似,如果你在这里写了多个模块,那么这些模块都会被打包成一个文件,如:

require(['./list', './edit'], function(list, edit){
list.show();
edit.display();
});

list.js和edit.js会被打包在一起。不同的是,AMD的方式无法传入第三个参数当文件名,所以得不到很好看的文件。

ES6 import

这年头不用ES6都不好意思跟人打招呼。所以我们的代码中,又会多一种模块引入语法,那就是import。import会被转化为commonjs格式或者是AMD格式,所以不要把它认为是一种新的模块引用方式。babel默认会把ES6的模块转化为commonjs规范的,你也不用费劲再把它转成AMD了。

所以如下写法是等价的:

import list from './list';
//等价于
var list = require('./list');

不过这两种写法只需选一种,避免在代码中同时使用两种,否则会造成混淆。

总结

以上把require的用法捋了一遍,明白了各自用法的区别之后,我们就可以在项目中进行选择了。我觉得最佳选择是往commonjs方向靠拢,想尝试ES6的话就用import代替commonjs同步语法即可。

因此,代码中保持以下两种风格就好:

//可打包在一起的同步代码,使用import语法
import list from './list'; //需要独立打包、异步加载的代码,使用require.ensure
require.ensure([], function(require){
var list = require('./list');
});

很显然,你在写代码的时候还是需要对打包结果进行决策,这是我不喜欢webpack的原因。gulp那样多好,编码就是编码,编译就是编译,分开来。不过这就是webpack以模块为核心的打包方式的特点吧,仁者见仁,只要团队内做一个约定,也不会打的一塌糊涂。

如果你是新手,对commonjs以及AMD的各自特点还不太清楚,推荐去看一下我之前写的这篇:js模块化历程

webpack解惑:require的五种用法的更多相关文章

  1. webpack解惑:require的五种用法 (转)

    我之前在 <前端搭环境之从入门到放弃>这篇文章中吐槽过,webpack中可以写commonjs格式的require同步语法,可以写AMD格式的require回调语法,还有一个require ...

  2. webpack中,require的五种用法

    a.js: module.exports = function(x){ console.log(x); } 一,commonjs同步: var b = require('./a');b('你好')// ...

  3. C#this的五种用法

    this的五种用法: 1.使用被掩盖的成员变量: class AA { int a; public void set1(int a) { this.a = a;//right } public voi ...

  4. Android Toast 总结(五种用法)

    Toast大家都很熟,不多说.直接上图上代码. 具体代码如下: main.xml: <?xml version="1.0" encoding="utf-8" ...

  5. Wix 安装部署教程(十五) --CustomAction的七种用法

    在WIX中,CustomAction用来在安装过程中执行自定义行为.比如注册.修改文件.触发其他可执行文件等.这一节主要是介绍一下CustomAction的7种用法. 在此之前要了解InstallEx ...

  6. route按需加载的3种方式:vue异步组件、es提案的import()、webpack的require.ensure()

    1. vue异步组件技术 vue-router配置路由,使用vue的异步组件技术,可以实现按需加载. 但是,这种情况下一个组件生成一个js文件.举例如下: { path: '/promisedemo' ...

  7. css详解position五种属性用法及其含义

    position(定位) position - 作为css属性三巨头(position.display.float)之一,它的作用是用来决定元素在文档中的定位方式.其属性值有五种,分别是 - stat ...

  8. EntityFramework嵌套查询的五种方法

    这样的双where的语句应该怎么写呢: var test=MyList.Where(a => a.Flows.Where(b => b.CurrentUser == “”) 下面我就说说这 ...

  9. 转:Windows Socket五种I/O模型

    原文转自:  Windows Socket五种I/O模型 Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模 ...

随机推荐

  1. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

  2. ABP文档 - 嵌入的资源文件

    文档目录 本节内容: 简介 创建嵌入的文件 暴露嵌入的文件 使用嵌入的文件 简介 一个web应用里,客户端包含javascript,css,xml等文件,这此文件被添加到一个web项目后,发布成独立的 ...

  3. Hyper-v 安装CentOS 7 (其他虚拟机一样参考)

    平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html hyper-v安装很多人没弄过,我这里介绍一下.(其他虚拟机参 ...

  4. Android raw to bmp

    Android raw 格式转 bmp 图像 raw 保存的为裸数据,转换时都需要把它转成RGBA 的方式来显示.其中: 8位RAW: 四位RGBA 来表示一位灰度; 24位RAW: 三位RGB相同, ...

  5. 快速搭建springmvc+spring data jpa工程

    一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...

  6. 用神奇的currentColor制作简洁的颜色动画效果

    先上一个兼容性总结图:老版本ie可以直接用复杂方法了,套用某表情包的话:  2016年了,做前端你还考虑兼容IE6?你这简直是自暴自弃! 好了,知道了兼容性,我们可以放心的使用了. 在CSS3中扩展了 ...

  7. ZKWeb网页框架1.1正式发布

    发行日志 https://github.com/zkweb-framework/ZKWeb/blob/master/ReleaseNotes/ReleaseNote.1.1.md 主要改动 添加EFC ...

  8. C++ 事件驱动型银行排队模拟

    最近重拾之前半途而废的C++,恰好看到了<C++ 实现银行排队服务模拟>,但是没有实验楼的会员,看不到具体的实现,正好用来作为练习. 模拟的是银行的排队叫号系统,所有顾客以先来后到的顺序在 ...

  9. Ajax使用WCF实现小票pos机打印源码

    通过ajax跨域方式调用WCF服务,实现小票pos机的打印,源码提供web方式,客户端方式测试,服务驻留右侧底部任务栏,可控制服务开启暂停,用户可自定义小票打印模板,配合零售录入. qq  22945 ...

  10. mount报错: you must specify the filesystem type

    在linux mount /dev/vdb 到 /home 分区时报错: # mount /dev/vdb /homemount: you must specify the filesystem ty ...