How to overwrite file with angular schematics?

走远了吗. 提交于 2019-12-03 10:42:41

I experienced the same issue. By accident I found that adding a forEach into the apply allowed the files to be deleted and the new files created. This is with @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);
    };
}

Modifying chris' answer I was able to come up with the following solution:

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);
  };
}

Replace your usage of apply with calls to this function.

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

This may not be ideal if you are replacing many files. I came across this issue replacing the favicon.ico while adding boilerplate to the project. The solution I use is to explicitly delete it first.

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);
  };
}

NOTE: This approach no longer works with current versions of Schematics.

The following seems to work for the 0.6.8 schematics.

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);
  };
}

As a bonus, I no longer need to explicitly delete the file.

Thanks @cgatian for that hint!
Unfortunately it didn't worked to move the templates to some location, so I had to add:

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;
})

Until the MergeStrategy works as expected,
this will do the trick passing the destination path in options.output!

Thanks again!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!