一、require() 的基本用法

分析源码之前,先介绍 require 语句的内部逻辑。如果你只想了解 require 的用法,只看这一段就够了。

下面的内容翻译自《Node使用手册》。

当 Node 遇到 require(X) 时,按下面的顺序处理。

(1)如果 X 是内置模块(比如 require('http')) 
  a. 返回该模块。 
  b. 不再继续执行。

(2)如果 X 以 "./" 或者 "/" 或者 "../" 开头 
  a. 根据 X 所在的父模块,确定 X 的绝对路径。 
  b. 将 X 当成文件,依次查找下面文件,只要其中有一个存在,就返回该文件,不再继续执行。

  • X
  • X.js
  • X.json
  • X.node

  c. 将 X 当成目录,依次查找下面文件,只要其中有一个存在,就返回该文件,不再继续执行。

  • X/package.json(main字段)
  • X/index.js
  • X/index.json
  • X/index.node

(3)如果 X 不带路径 
  a. 根据 X 所在的父模块,确定 X 可能的安装目录。 
  b. 依次在每个目录中,将 X 当成文件名或目录名加载。

(4) 抛出 "not found"

请看一个例子。

当前脚本文件 /home/ry/projects/foo.js 执行了 require('bar') ,这属于上面的第三种情况。Node 内部运行过程如下。

首先,确定 x 的绝对路径可能是下面这些位置,依次搜索每一个目录。


/home/ry/projects/node_modules/bar
/home/ry/node_modules/bar
/home/node_modules/bar
/node_modules/bar

搜索时,Node 先将 bar 当成文件名,依次尝试加载下面这些文件,只要有一个成功就返回。


bar
bar.js
bar.json
bar.node

如果都不成功,说明 bar 可能是目录名,于是依次尝试加载下面这些文件。


bar/package.json(main字段)
bar/index.js
bar/index.json
bar/index.node

如果在所有目录中,都无法找到 bar 对应的文件或目录,就抛出一个错误。

二·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实现了它,作用是可以在打包的时候进行代码分片,并异步加载分片后的代码。用法如下:

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

  

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

1.fb874860b35831bc96a8.js

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

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

  

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

list.fb874860b35831bc96a8.js

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

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

1
2
3
4
5
6
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的第一个参数传了空数组,实际上这里是可以接收模块名称的,作用就是实现预加载懒执行。用法如下:

1
2
3
4
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自己提供的,并没有什么规范做后台,所以是个小角色。它可以实现上面是预加载功能,而不用把模块写在数组中,用法如下:

1
2
3
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的经典语法是可以正常使用的,如:

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

  

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

1
2
3
4
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了。

所以如下写法是等价的:

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

  

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

总结

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

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

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

  

webpack中require的用法相关推荐

  1. php require的用法,PHP 中 require 的用法

    PHP 中 require 的用法 在PHP中require语句作用是包含并运行指定文件,与include的区别:include在引入不存文件时产生一个警告且脚本还会继续执行,而require则会导致 ...

  2. js语句连接mysql数据库_js中require()的用法----JS如何连接数据库执行sql语句或者建立数据库连接池...

    var vue = require('vue'); 引入vue的意思,commonjs的写法.node都是用require来载入模块的,可以看看webpack+vue. require()可以调用模块 ...

  3. php中require的用法,PHP中require()的妙用

    require()一般用于引入文件,然而,它居然还可以有返回值: $r = require('config.php'); 当然,config.php需要像方法一样给出返回值: return array ...

  4. Vue 单文件组件||Vue 单文件组件的基本用法||webpack 中配置 vue 组件的加载器|| 在 webpack 项目中使用 vue

    Vue 单文件组件 传统组件的问题和解决方案 1. 问题 1. 全局定义的组件必须保证组件的名称不重复 2. 字符串模板缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的 \ 3. 不支持 CS ...

  5. 六、Webpack详解学习笔记——webpack的安装、起步、配置、loader的使用、webpack中配置Vue、plugin的使用、搭建本地服务器、webpack配置的分离

    一.认识webpack 什么是webpack? 这个webpack还真不是一两句话可以说清楚的. 我们先看看官方的解释: At its core, webpack is a static module ...

  6. webpack 打包html中css样式如果处理,webpack中单独打包css样式

    这次给大家带来webpack中单独打包css样式,webpack中单独打包css样式的注意事项有哪些,下面就是实战案例,一起来看一下. 零.介绍 以下是个人项目中总结出来的一些基本知识,记录在这里,加 ...

  7. static图片编译了 vue_详解vue-cil和webpack中本地静态图片的路径问题解决方案

    本文介绍了vue-cil和webpack中本地静态图片的路径问题解决方案,分享给大家,具体如下: 1 本地图片动态绑定img的src属性 一般我们在html中或者vue组件文件中引用图片是这样,这是不 ...

  8. 在Vue的webpack中结合runder函数

    在Vue的webpack中结合runder函数 1.引入: <h1>下面是vue的内容:</h1><div id="app"><login ...

  9. Node.js webpack中导入vue的三种方法

    在webpack 中使用 Vue: 安装 vue 模块 npm i vue -S 注意: 在 webpack 中, 使用 import Vue from 'vue' 导入的 Vue 构造函数,功能不完 ...

最新文章

  1. 图片右击打印不弹出打印首选项
  2. 重新格式化NameNode后,DataNode启动不起来问题解决
  3. Linux基础命令--常用命令工具
  4. RabbitMQ和Kafka的显著差异(2)
  5. leetcode 并查集 547.省份数量/200岛屿数量
  6. Windows server 2016 部署AD(Windows 域)
  7. Hector代码笔记
  8. 装linux后分区丢失吗,找到了linux分区顺序错乱修复方法
  9. 材料表征技术书籍-7本
  10. Android实现AirPlay,DriodAirPlay开发
  11. 逍遥模拟器1 android,逍遥安卓模拟器5.1.1
  12. Spark基本工作流程和作业调度
  13. 管理远程团队的4种方法
  14. 【Excel】工作表的并排比较
  15. python 学习笔记第一篇---下载网页内所有图片
  16. 基于python的土壤细菌在kobas库的功能预测代码
  17. pe重装系统后F盘无法打开系统拒绝访问解决方案
  18. 高阶函数、列表/集合/字典/推导式、递归函数
  19. 计算机的ram是一种什么东西,科技:什么是RAM?
  20. 【掘金使用技巧7】如何从通达信等迁移到掘金

热门文章

  1. 10亿计算下的合约广告,如何做个性化投放?
  2. HTML DOM Table对象insertRow()方法与deleteRow()方法
  3. 十、Openpyxl自定义单元格样式
  4. 微信小程序-开发经验总结---(基础重点)
  5. linux设备描述文件,iOS开发 - 超级签名实现之描述文件
  6. 计算机语言排行榜--让你更好的选择
  7. SWUST OJ 978: 输出利用先序遍历创建的二叉树的中序遍历序列
  8. 乍暖还寒时候,火锅不能停
  9. maya动画制作(4)——小男孩的各种姿态动画制作(修改更新)
  10. 设计模式(四)【Strategy模式】