使用 grunt-init 创建项目时如何自定义模板变量

解读

在国内前端面试中,**“grunt-init 自定义模板变量”**常被用来考察候选人对 Grunt 生态深度定制能力。
面试官真正想听的是:

  1. 你是否理解 grunt-init 的模板替换机制(基于 <%= prop %> 占位符);
  2. 你是否能不改动全局模板的前提下,为团队沉淀一套“私有可复用”模板;
  3. 你是否知道prompt.json 与 template.js 的配合方式,以及如何把公司规范(如私有 npm 源、CDN 路径、内部 GitLab 地址)注入到新建项目里。
    答不到“私有模板目录 + prompt 扩展 + 默认值回写”这三点,基本会被判定为“只会用现成模板”。

知识点

  1. grunt-init 模板目录结构
    • root/:原样拷贝的文件
    • template.js:唯一入口,通过 init.process 控制文件渲染与重命名
    • template/:含 <%= var %> 占位符的待渲染文件
  2. 变量来源优先级
    • 内置变量(name、author、email 等)
    • prompt.json 自定义交互字段(可被 init.prompts 扩展)
    • defaults.json 静默默认值(适合 CI 场景)
  3. 自定义流程
    • 本地模板放置路径:~/.grunt-init/xxx(Windows 下为 %USERPROFILE%.grunt-init\xxx)
    • 在 template.js 里用 init.prompts 追加问题,并通过 init.process 把答案写入 props
    • 模板文件中用 <%= props.pluginName %> 形式取值,支持 .camelCase、.slugify 等 Underscore 模板函数
  4. 国内常见定制项
  5. 调试技巧
    • --debug 参数可打印 props 对象,确认变量是否注入成功
    • 使用 init.writePackageJSON 二次回写,保证 package.json 字段与团队规范完全一致

答案

步骤如下:

  1. 在本地私有模板目录新建文件夹,例如 ~/.grunt-init/vue-mobile
  2. 创建 prompt.json,追加公司需要的变量:
    {
      "registry": {
        "type": "input",
        "message": "私有 npm 源地址",
        "default": "https://registry.npmmirror.com"
      },
      "cdnPrefix": {
        "type": "input",
        "message": "静态资源 CDN 前缀",
        "default": "//static.example.com"
      }
    }
    
  3. template.js 中把自定义字段合并到 props:
    exports.template = function(grunt, init, done) {
      init.process({type: 'jquery'}, [
        init.prompt('name'),
        init.prompt('registry'),
        init.prompt('cdnPrefix')
      ], function(err, props) {
        props.devDependencies = {grunt: '^1.6.0'};
        // 把 registry 写入 .npmrc 模板
        props.npmrc = 'registry=' + props.registry;
        // 生成文件
        var files = init.filesToCopy(props);
        init.copyAndProcess(files, props);
        // 二次回写 package.json
        init.writePackageJSON('package.json', props, function(pkg) {
          pkg.cdnPrefix = props.cdnPrefix;
          return pkg;
        });
        done();
      });
    };
    
  4. template/.npmrc 中写入:
    <%= npmrc %>
    
  5. 运行 grunt-init vue-mobile,交互阶段会提示输入 registry 与 cdnPrefix,回车后所有占位符被替换,项目即按公司规范初始化完成。

拓展思考

  1. 如何共享私有模板
    把模板目录推送到内部 GitLab,再写个 CLI 脚本:git clone 到 ~/.grunt-init/ 并自动重命名,实现“一键同步团队模板”。
  2. 如何让 grunt-init 与 Yeoman 共存
    老项目用 grunt-init 维护,新项目用 Yeoman generator,但统一在 meta 文件里记录模板版本号,保证构建产物可追踪。
  3. 如何在 CI 中无交互使用
    defaults.json 中预置所有变量,执行 grunt-init xxx --default,配合 Docker 可在 5 秒内拉起一个标准化前端项目。