问题是什么

我们在使用requirejs进行模块化开发的时候,通常务必会有一个入口脚本,在这里比如我们叫做main.js,最近我发现,main.js与其他模块在文件中的关系可能是需要小心的组织,否则会在打包中发生一些问题。比如下面这种情况:

|--build // 打包输出目录
|--build.js // 打包脚本
|--main.js // 模块入口
|--src // 源码目录
    |--foo_module.js
    |--bar_module.js
    |--lib
        |--jQuery.js
        |--Bakcbone.js

这种情况的特点是,入口main.js和其他的模块并不在同一目录中。

此时你的build.js可能会这么写:

({
    baseUrl: './',
    name: "./main",
    out: "./build/main-built.js"
})

So far so good。因为main.js与其他模块并非在同一目录中,因此main.js同样也需要进行配置:

requirejs.config({
    baseUrl: "./src",
    paths: {
        "jQuery": "./lib/jquery"
    }
});

无论是打包配置还是开发配置中,baseUrl都表示着查找模块的相对路径。所以模块的查找都是基于baseUrl

OK,那问题来了,当你使用build.js开始进行打包时,配置的根目录为当前根目录./。此时打包脚本找到了main.js。并需要继续打包main的依赖模块。但此时需要根据main.js中的配置requirejs.config重置查找模块的相对路径为./src。但打包脚本不存在这样的机制,仍然在根目录查找模块,于是就报错了

或者简单来说,导致这个问题的原因是下面两点

  1. 打包所使用的基本目录与开发所使用的基本目录不一致
  2. 在打包过程中,打包脚本无法读取开发中的配置。

所以可见问题在于build.js与main.js所使用的基本路径不一致。

解决方案

很简单,把main.js和其他模块都放在同一级目录即可。

|--build.js // 打包脚本
|--src // 源码目录
    |--main.js // 模块入口
    |--foo_module.js
    |--bar_module.js
    |--lib
        |--jQuery.js
        |--Bakcbone.js

那么即使build.js与main.js都配置了打包目录,都应该指向的是main.js所在的/src目录。

打包脚本的配置肯定已经比我们先考虑到了这个问题,在打包配置中有这样一个字段mainConfigFile,用来单独指定有关main.js的配置文件,这也就意味着main.js与build.js公用同一个配置文件,在这里我们比如叫config.js。看上去很美好,但并不适用,比如第一个问题就是如何在main.js中如何引入config.js?

  1. 方法一:把config.js中的内容在main.js中再复制一遍。也就是同时维护两份相同内容的代码。

  2. 方法二: 把config.js在main中引入,而main.js中首先引入config.js。比如这个样子:

require(["./config"], function () {
    // main.js实际上从这里才开始
    require(["foo", "bar"], function () {

    });
});

这样看上去很好,其实是有很大问题的,main函数在工厂函数之中,会导致打包的时候脚本无法解析main函数的依赖(也就是无法解析foo与bar),它只认得最外层的require(["./config"]);

所以方法一有维护成本,方法二根本不可行。

##总结

所以孩子,最好还是把main.js入口模块和其他模块放在同一级目录中吧。

全世界都想让程序员专心写业务代码

最近两年我不知道你是否和我拥有同样的感受,编程容易了许多,同时乐趣也少了许多## 一最近有两个契机让我写这篇文章,一是过去一年我陆续把我所有 side project 后端从 Azure App Service 迁移到 Digital Ocean(以下简称 DC) 的 Dr...… Continue reading

Copilot 结对编程指南

发布于 2024年01月18日

Tech Lead 要学会戴着镣铐跳舞

发布于 2023年11月26日