【问题标题】:How to overwrite file with angular schematics?如何用角度示意图覆盖文件?
【发布时间】:2018-08-04 01:23:01
【问题描述】:

我想写一个Rule,它每次都会覆盖一个文件。在下面并将MergeStrategy 设置为Overwrite

collection.json

{
  "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
  "schematics": {
    "function": {
      "aliases": [ "fn" ],
      "factory": "./function",
      "description": "Create a function.",
      "schema": "./function/schema.json"
    }
  }
}

function/index.ts

export default function(options: FunctionOptions): Rule {
  options.path = options.path ? normalize(options.path) : options.path;
  const sourceDir = options.sourceDir;
  if (!sourceDir) {
    throw new SchematicsException(`sourceDir option is required.`);
  }

  const templateSource: Source = apply(
    url('./files'),
    [
      template({
        ...strings,
        ...options,
      }),
      move(sourceDir),
    ]
  )

  return mergeWith(templateSource, MergeStrategy.Overwrite);

}

files/__path__/__name@dasherize__.ts

export function <%= camelize(name) %>(): void {
}

我运行schematics .:function --name=test --dry-run=false 我得到了

创建 /src/app/test.ts(33 字节)

但是,第二次。

错误! /src/app/test.ts 已经存在。

它不应该覆盖文件test.ts而不出错吗?

编辑:

所有答案都有效并且很棒,但似乎它们是变通方法,没有明显的“正确”答案,并且可能基于偏好/自以为是。所以不知道如何标记为已回答。

【问题讨论】:

  • 实际上不,默认行为是保留文件原样。您可以使用--force 标志来强制覆盖文件,如下所示:schematics .:function --name=test --dry-run=false --force。 BTW:你在模板函数中为...strings 导入了什么?
  • 我可能不明白MergeStrategy.Overwrite 的含义,如果那不是行为那么MergeStrategy.Overwrite 的意义/意义是什么。
  • 哦,对不起,我完全错过了MergeStrategy.Overwrite,现在我同意它应该完全有效。至少在归档的 angular/dev-kit 项目中曾经存在过一个问题:github.com/angular/devkit/issues/745
  • @jlang import { strings } from '@angular-devkit/core';

标签: angular angular-cli angular-schematics


【解决方案1】:

如果您要替换许多文件,这可能并不理想。我在向项目添加样板时遇到了替换 favicon.ico 的问题。我使用的解决方案是先显式删除它。

export function scaffold(options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
  
    tree.delete('src/favicon.ico');

    const templateSource = apply(url('./files'), [
      template({
        ...options,
      }),
      move('.'),
    ]);

    return chain([
      branchAndMerge(chain([
        mergeWith(templateSource, MergeStrategy.Overwrite),
      ]), MergeStrategy.AllowOverwriteConflict),
    ])(tree, _context);
  };
}

注意:此方法不再适用于当前版本的 Schematics。

以下似乎适用于 0.6.8 原理图。

export function scaffold(options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
  
    const templateSource = apply(url('./files'), [
      template({
        ...options,
      }),
      move('.'),
    ]);

    return chain([
      branchAndMerge(chain([
        mergeWith(templateSource, MergeStrategy.Overwrite),
      ]), MergeStrategy.Overwrite),
    ])(tree, _context);
  };
}

作为奖励,我不再需要明确删除文件。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题。我偶然发现在apply 中添加forEach 可以删除文件并创建新文件。这是@angular-devkit/schematics-cli@0.6.8。

    export function indexPage(options: any): Rule {
        return (tree: Tree, _context: SchematicContext) => {
            const rule = mergeWith(
                apply(url('./files'), [
                    template({ ...options }),
                    forEach((fileEntry: FileEntry) => {
                        // Just by adding this is allows the file to be overwritten if it already exists
                        if (tree.exists(fileEntry.path)) return null;
                        return fileEntry;
                    })
    
                ])
            );
    
            return rule(tree, _context);
        };
    }
    

    【讨论】:

    • 该死的,这不适用于嵌套文件夹结构。当心!
    • 我将它与嵌套文件夹一起使用,深度为两层。但是我确实发现如果文件不存在会出错,所以我必须先添加一个检查是否存在。我会更新我的答案。
    • 对于 forEach() 最后很重要,我发现 ie 在 move() 之后
    • 这个答案不正确。它不会覆盖现有文件 - 只会忽略它们而不抛出“Schematics process failed”错误。 @cgatian 的回答确实会覆盖现有文件。
    【解决方案3】:

    修改克里斯的回答我能够想出以下解决方案:

    export function applyWithOverwrite(source: Source, rules: Rule[]): Rule {
      return (tree: Tree, _context: SchematicContext) => {
        const rule = mergeWith(
          apply(source, [
            ...rules,
            forEach((fileEntry) => {
              if (tree.exists(fileEntry.path)) {
                tree.overwrite(fileEntry.path, fileEntry.content);
                return null;
              }
              return fileEntry;
            }),
    
          ]),
        );
    
        return rule(tree, _context);
      };
    }
    

    将您对apply 的使用替换为对该函数的调用。

     applyWithOverwrite(url('./files/stylelint'), [
            template({
              dot: '.',
            }),
          ]),
    

    【讨论】:

    • 这个解决方案实际上覆盖了现有文件(而不是接受的文件),谢谢 :) N.B.由于某种原因,WebStorm 看不到它可以从哪里导入 forEach 和 FileEntry;它应该从 '@angular-devkit/schematics' 导入
    • 如果forEach 之前的...rules 之一创建了该文件,则tree.exists(fileEntry.path) 将评估为true。换句话说,该文件可能实际上并不存在于您的文件系统中,而仅存在于由原理图构建的虚拟树中。考虑到您的用例,这可能很重要,也可能无关紧要。
    【解决方案4】:

    感谢@cgatian 的提示!
    不幸的是,它无法将模板 move 放到某个位置,所以我不得不添加:

    forEach(fileEntry => {
      const destPath = join(options.output, fileEntry.path);
      if (tree.exists(destPath)) {
        tree.overwrite(destPath, fileEntry.content);
      } else {
        tree.create(destPath, fileEntry.content);
      }
      return null;
    })
    

    直到MergeStrategy 按预期工作,
    这将在options.output 中传递目标路径!

    再次感谢!

    【讨论】:

      【解决方案5】:

      使用--force 参数: ng g c component-name --force

      【讨论】:

        猜你喜欢
        • 2018-12-24
        • 2019-08-07
        • 2020-01-27
        • 2018-11-15
        • 2018-12-07
        • 2020-08-19
        • 2019-10-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多