用rollup.js构建Angular模块:外部html模板文件不起作用(404)

时间:2018-01-13 19:17:26

标签: angular typescript rollupjs angular-library

我正在开发一个Angular lib(GitHub repo link),有

  • lib模块源位于./src
  • 测试放置在./app
  • 的应用来源
  • lib分配在./dist

构建过程使用 rollup.js ,并基于angular-library-starter。 我还有一个从./dist生成npm包的进程,并将其安装到./node_modules。问题是该应用程序适用于从./src导入的lib模块,并且在我从./dist./node_modules导入时无效:

// ./app/app/app.module.ts
import { AppComponent } from './app.component';
import { UiScrollModule } from '../../src/ngx-ui-scroll';   // works
//import { UiScrollModule } from 'ngx-ui-scroll';           // doesn't work
//import { UiScrollModule } from '../../dist/bundles/ngx-ui-scroll.umd.js'; // no...

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, UiScrollModule],
  bootstrap: [AppComponent]
})
export class AppModule { }

构建过程中没有错误,但浏览器控制台说(对于./dist./node_modules导入案例):

  

获取http://localhost:4200/ui-scroll.component.html 404(未找到)
  无法加载ui-scroll.component.html

我的lib模块确实有一个具有外部temlate的组件:

// ./src/component/ui-scroll.component.ts
@Component({
  selector: 'app-ui-scroll',
  templateUrl: './ui-scroll.component.html'
})
export class UiScrollComponent implements OnInit, OnDestroy { /* ... */ }

如果我要内嵌模板(在template设置中使用templateUrl而不是@Component),它会起作用,我对其进行了测试。但我希望模板位于单独的文件中......我相信这是一个构建过程的责任。有一堆与我的构建过程相关的配置,我认为在这里列出它们并不是一个好主意。可以在lib repository找到它们(或者我可以根据要求发布任何确切的部分)。

有没有人遇到过外部html模板汇总捆绑的问题?

1 个答案:

答案 0 :(得分:2)

  

我认为这是构建过程的责任。

好像你是对的。我们通常在构建过程中内联模板。

为了做到这一点,您可以创建如下的js文件:

<强> /utils/inline-resouces.js

const {dirname, join} = require('path');
const {readFileSync, writeFileSync} = require('fs');
const glob = require('glob');

/** Finds all JavaScript files in a directory and inlines all resources of Angular components. */
module.exports = function inlineResourcesForDirectory(folderPath) {
  glob.sync(join(folderPath, '**/*.js')).forEach(filePath => inlineResources(filePath));
};

/** Inlines the external resources of Angular components of a file. */
function inlineResources(filePath) {
  let fileContent = readFileSync(filePath, 'utf-8');

  fileContent = inlineTemplate(fileContent, filePath);
  fileContent = inlineStyles(fileContent, filePath);

  writeFileSync(filePath, fileContent, 'utf-8');
}

/** Inlines the templates of Angular components for a specified source file. */
function inlineTemplate(fileContent, filePath) {
  return fileContent.replace(/templateUrl:\s*'([^']+?\.html)'/g, (_match, templateUrl) => {
    const templatePath = join(dirname(filePath), templateUrl);
    const templateContent = loadResourceFile(templatePath);

    return `template: "${templateContent}"`;
  });
}

/** Inlines the external styles of Angular components for a specified source file. */
function inlineStyles(fileContent, filePath) {
  return fileContent.replace(/styleUrls:\s*(\[[\s\S]*?])/gm, (_match, styleUrlsValue) => {
    // The RegExp matches the array of external style files. This is a string right now and
    // can to be parsed using the `eval` method. The value looks like "['AAA.css', 'BBB.css']"
    const styleUrls = eval(styleUrlsValue);

    const styleContents = styleUrls
      .map(url => join(dirname(filePath), url))
      .map(path => loadResourceFile(path));

    return `styles: ["${styleContents.join(' ')}"]`;
  });
}

/** Loads the specified resource file and drops line-breaks of the content. */
function loadResourceFile(filePath) {
  return readFileSync(
      filePath.replace('dist\\package\\esm5\\', '').replace('dist\\', ''), 'utf-8')
    .replace(/([\n\r]\s*)+/gm, ' ')
    .replace(/"/g, '\\"');
}

然后按如下方式更改build.js文件:

<强> build.js

...
const ESM5_DIR = `${NPM_DIR}/esm5`;
const BUNDLES_DIR = `${NPM_DIR}/bundles`;
const OUT_DIR_ESM5 = `${NPM_DIR}/package/esm5`;

// 1) import function from created above file
const inlineResourcesForDirectory = require('./utils/inline-resources');
// 1) end

...

/* AoT compilation */
shell.echo(`Start AoT compilation`);
if (shell.exec(`ngc -p tsconfig-build.json`).code !== 0) {
  shell.echo(chalk.red(`Error: AoT compilation failed`));
  shell.exit(1);
}
shell.echo(chalk.green(`AoT compilation completed`));

// 2) Inline template after first ngc build
shell.echo(`Start inlining templates in ${NPM_DIR} folder`);
inlineResourcesForDirectory(NPM_DIR);
shell.echo(`Inlining templates in ${NPM_DIR} folder completed`);
// 2) end

...

shell.echo(`Produce ESM5 version`);
shell.exec(`ngc -p tsconfig-build.json --target es5 -d false --outDir ${OUT_DIR_ESM5} --importHelpers true --sourceMap`);

// 3) Inline template after second ngc build
shell.echo(`Start inlining templates in ${OUT_DIR_ESM5} folder`);
inlineResourcesForDirectory(OUT_DIR_ESM5);
shell.echo(`Inlining templates in ${OUT_DIR_ESM5} folder completed`);
// 3) end

if (shell.exec(`rollup -c rollup.es.config.js -i ${OUT_DIR_ESM5}/${PACKAGE}.js -o ${ESM5_DIR}/${PACKAGE}.js`).code !== 0) {

完成上述所有3次更改后,您可以检查您的ngx-ui-scroll.umd.js捆绑包。它应该看起来像:

enter image description here

另见