Webpack不解析第三方库的扩展

时间:2017-03-15 16:54:29

标签: angular typescript webpack sass-loader raw-loader

我正在开发2个Angular 2库:

  1. carbonldp-工作台
  2. carbonldp面板
  3. Project2(面板):

    是要导出的组件和模块的集合。这些组件有自己的模板和scss文件。该库是使用Typescript编写的,但dist文件正在编译中,因此该库作为npm包提供,其中包含.js.metadata.json个文件及其.d.ts及其{ {1}}个文件。

    Project1(工作台)

    是主要项目。它使用 Project2 ,因此它可以工作。 这个项目使用Webpack捆绑最终的应用程序。问题是我不能让webpack与Project2(Panel)一起工作,因为主项目是用typescript编写的,面板只用javascript文件导入。 我从webapack获得的错误是找不到Project2中的所有模板文件。见下文:

    enter image description here

    这是最终的app.js捆绑 Project2 库的方式,请注意来自 Project2 的标头组件如何导入模板文件:< / p>

    enter image description here

    请注意webpack如何从项目 Project1 (用ts编写)导入模板和样式文件:

    enter image description here

    这就是我在webpack.config.js文件中定义解析扩展名的规则的方法:

    entry: {
        "polyfills": "./src/polyfills.ts",
        "app": "./src/main.ts"
    },
    
    resolve: {
        extensions: [ ".ts", ".js" ],
        alias: {
            "app": helpers.root( "src", "app" ),
            "jquery": "jquery/src/jquery",
            "semantic-ui": helpers.root( "src/semantic/dist" ),
        },
        modules: [ helpers.root( "node_modules" ) ]
    },
    
    module: {
        rules: [
                {
                    test: /\.ts$/,
                    use: [ "awesome-typescript-loader", "angular2-template-loader", "angular-router-loader" ]
                },
                {
                    test: /\.html$/,
                    use: "raw-loader",
                    exclude: [ helpers.root( "src/index.html" ) ]
                },
                {
                    test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
                    use: "file-loader?name=assets/[name].[hash].[ext]"
                },
                {
                    test: /\.s?css$/,
                    use: [ "raw-loader", "sass-loader" ]
                },
            ]
        },
    

    这里的问题是...... 如何 我可以让Webpack也编译我的角度js库的导入?

1 个答案:

答案 0 :(得分:1)

根据我的经验,angular2-template-loader不会深入到node_modules中,因此node_modules中可能依赖于它的库将是不合时宜的。

我解决这个问题的方法是将外部模板和css文件作为库构建步骤的一部分进行内联,并且我很大程度上依赖于角度材质2如何发布它们的库。然后webpack - 在消费应用程序级别 - 不需要担心你的模板或样式表,因为他们已经准备好了。

为了不使用链接,这里是他们的脚本,我不赞成它:

#!/usr/bin/env node
'use strict';

const fs = require('fs');
const path = require('path');
const glob = require('glob');

/**
 * Simple Promiseify function that takes a Node API and return a version that supports promises.
 * We use promises instead of synchronized functions to make the process less I/O bound and
 * faster. It also simplify the code.
 */
function promiseify(fn) {
  return function() {
    const args = [].slice.call(arguments, 0);
    return new Promise((resolve, reject) => {
      fn.apply(this, args.concat([function (err, value) {
        if (err) {
          reject(err);
        } else {
          resolve(value);
        }
      }]));
    });
  };
}

const readFile = promiseify(fs.readFile);
const writeFile = promiseify(fs.writeFile);


function inlineResources(globs) {
  if (typeof globs == 'string') {
    globs = [globs];
  }

  /**
   * For every argument, inline the templates and styles under it and write the new file.
   */
  return Promise.all(globs.map(pattern => {
    if (pattern.indexOf('*') < 0) {
      // Argument is a directory target, add glob patterns to include every files.
      pattern = path.join(pattern, '**', '*');
    }

    const files = glob.sync(pattern, {})
      .filter(name => /\.js$/.test(name));  // Matches only JavaScript files.

    // Generate all files content with inlined templates.
    return Promise.all(files.map(filePath => {
      return readFile(filePath, 'utf-8')
        .then(content => inlineResourcesFromString(content, url => {
          return path.join(path.dirname(filePath), url);
        }))
        .then(content => writeFile(filePath, content))
        .catch(err => {
          console.error('An error occurred: ', err);
        });
    }));
  }));
}

/**
 * Inline resources from a string content.
 * @param content {string} The source file's content.
 * @param urlResolver {Function} A resolver that takes a URL and return a path.
 * @returns {string} The content with resources inlined.
 */
function inlineResourcesFromString(content, urlResolver) {
  // Curry through the inlining functions.
  return [
    inlineTemplate,
    inlineStyle,
    removeModuleId
  ].reduce((content, fn) => fn(content, urlResolver), content);
}

if (require.main === module) {
  inlineResources(process.argv.slice(2));
}


/**
 * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and
 * replace with `template: ...` (with the content of the file included).
 * @param content {string} The source file's content.
 * @param urlResolver {Function} A resolver that takes a URL and return a path.
 * @return {string} The content with all templates inlined.
 */
function inlineTemplate(content, urlResolver) {
  return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function(m, templateUrl) {
    const templateFile = urlResolver(templateUrl);
    const templateContent = fs.readFileSync(templateFile, 'utf-8');
    const shortenedTemplate = templateContent
      .replace(/([\n\r]\s*)+/gm, ' ')
      .replace(/"/g, '\\"');
    return `template: "${shortenedTemplate}"`;
  });
}


/**
 * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and
 * replace with `styles: [...]` (with the content of the file included).
 * @param urlResolver {Function} A resolver that takes a URL and return a path.
 * @param content {string} The source file's content.
 * @return {string} The content with all styles inlined.
 */
function inlineStyle(content, urlResolver) {
  return content.replace(/styleUrls:\s*(\[[\s\S]*?\])/gm, function(m, styleUrls) {
    const urls = eval(styleUrls);
    return 'styles: ['
      + urls.map(styleUrl => {
          const styleFile = urlResolver(styleUrl);
          const styleContent = fs.readFileSync(styleFile, 'utf-8');
          const shortenedStyle = styleContent
            .replace(/([\n\r]\s*)+/gm, ' ')
            .replace(/"/g, '\\"');
          return `"${shortenedStyle}"`;
        })
        .join(',\n')
      + ']';
  });
}


/**
 * Remove every mention of `moduleId: module.id`.
 * @param content {string} The source file's content.
 * @returns {string} The content with all moduleId: mentions removed.
 */
function removeModuleId(content) {
  return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
}


module.exports = inlineResources;
module.exports.inlineResourcesFromString = inlineResourcesFromString;

他们将此作为gulp任务的一部分,我将我的工作改为简单的节点脚本。

我在构建中所做的是:

  • 从我的src文件夹创建一个dist文件夹(所以html和css文件保持相对),然后从dist中:
    • 如果需要,在这里进行任何类型的postcss处理(使用postcss最好的选择是使用replace标志来维护文件夹结构)
    • 运行inliner(上面的脚本)
    • 删除html和css文件(不再需要它们)
    • 使用ngc进行翻译

在第一步中,我开始使用暂存文件夹,然后转换为dist文件夹,但是ngc没有与outDir一起播放。

这需要一段时间来解决这个问题,所以希望我可以节省你一些时间。