async _renderFile({ fileSrc, fileDest, fileDestAlt, data }) {
    // site
    const site = data.site;
    // language
    const language = site.language && site.language.current;
    // src
    const pathIntermediate = await this.getPathIntermediate(language);
    const fileName = path.join(pathIntermediate, fileSrc);
    // dest
    const pathDist = await this.getPathDist(site, language);
    const fileWrite = path.join(pathDist, fileDest);
    // data
    data._filename = fileName;
    data._path = fileSrc.replace('.ejs', '');
    // env site
    data.env('site.path', data._path);
    // destFile for hot load
    let hotloadFile;
    if (data.article) {
      hotloadFile = `atom/${data.article.atomId}`;
      // update renderAt
      data.article.renderAt = new Date(this.ctx.bean.util.moment().unix() * 1000);
    } else {
      if ((this.app.meta.isTest || this.app.meta.isLocal) && fileDest.indexOf('.html') > -1) {
        hotloadFile = fileWrite;
        data.env('site.hotloadFile', hotloadFile);
      }
    }
    // load src
    let contentSrc = await fse.readFile(fileName);
    contentSrc = contentSrc ? contentSrc.toString() : '';
    // load includes of plugins
    const pluginIncludes = await this._loadPluginIncludes({ site, language });
    contentSrc = `${pluginIncludes}\n${contentSrc}`;
    // render
    const options = this.getOptions();
    options.filename = fileName;
    let content = await ejs.render(contentSrc, data, options);
    content = await this._renderEnvs({ data, content });
    content = await this._renderCSSJSes({ data, content });
    // write
    await fse.outputFile(fileWrite, content);
    // alternative url
    if (fileDestAlt && fileDestAlt !== fileDest) {
      const fileWriteAlt = path.join(pathDist, fileDestAlt);
      await fse.outputFile(fileWriteAlt, content);
    }
    // renderAt must be updated after file rendered
    if (data.article) {
      // update renderAt
      await this.ctx.model.query(
        `
          update aCmsArticle set renderAt=?
            where iid=? and atomId=?
          `,
        [data.article.renderAt, this.ctx.instance.id, data.article.atomId]
      );
    }
    // socketio publish
    if (hotloadFile) {
      await this._socketioPublish({ hotloadFile, article: data.article });
    }
  }
/*.ejs`);
    for (const item of indexFiles) {
      // data
      const data = await this.getData({ site });
      // path
      const _fileSrc = item.substr(pathIntermediate.length + 1);
      let _fileDest = _fileSrc.substr('main/index/'.length).replace('.ejs', '');
      if (_fileDest.indexOf('.') === -1) {
        _fileDest = `${_fileDest}.html`;
      }
      await this._renderFile({
        fileSrc: _fileSrc,
        fileDest: _fileDest,
        data,
      });
    }
  }

  async _writeSitemaps({ site, articles }) {
    // xml
    let xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
`;
    for (const article of articles) {
      const loc = this.getUrl(site, site.language && site.language.current, article.url);
      const lastmod = moment(article.updatedAt).format();
      xml += `  <url>
    <loc>${loc}</loc>
    <lastmod>${lastmod}</lastmod>
  </url>
`;
    }
    xml += '</urlset>';
    // save
    const pathDist = await this.getPathDist(site, site.language && site.language.current);
    const fileName = path.join(pathDist, 'sitemap.xml');
    await fse.writeFile(fileName, xml);
  }

  async _writeSitemap({ site, article }) {
    const loc = this.getUrl(site, site.language && site.language.current, article.url);
    const lastmod = moment(article.updatedAt).format();
    // load
    const pathDist = await this.getPathDist(site, site.language && site.language.current);
    const fileName = path.join(pathDist, 'sitemap.xml');
    let xml;
    const exists = await fse.pathExists(fileName);
    if (!exists) {
      xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>${loc}</loc>
    <lastmod>${lastmod}</lastmod>
  </url>
</urlset>`;
    } else {
      xml = await fse.readFile(fileName);
      xml = xml.toString();
      // remove
      const regexp = new RegExp(` {2}<url>\\s+<loc>[^<]*${article.url}[^<]*</loc>[\\s\\S]*?</url>[\\r\\n]`);
      xml = xml.replace(regexp, '');
      // append
      xml = xml.replace(
        '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
        `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>${loc}</loc>
    <lastmod>${lastmod}</lastmod>
  </url>`
      );
    }
    // save
    await fse.writeFile(fileName, xml);
  }

  async _renderStatic({ site }) {
    // static
    const pathIntermediate = await this.getPathIntermediate(site.language && site.language.current);
    const staticFiles = await eggBornUtils.tools.globbyAsync(`${pathIntermediate}/static/*