【问题标题】:angular2-template-loader produces incorrect output, why?angular2-template-loader 产生不正确的输出,为什么?
【发布时间】:2016-12-31 21:43:40
【问题描述】:

请注意以下 TypeScript 文件:

import { Component } from "@angular/core";

@Component({
    selector: 'app-root',
    templateUrl: './app/app.component.html'
})
export class AppComponent {
}

在我使用 angular2-template-loader 之前它工作正常。当我尝试使用后者并运行 webpack 时,它会失败并显示以下消息:

    polyfills.js     283 kB       1  [emitted]  polyfills
       vendor.js    3.32 MB       2  [emitted]  vendor
     main.js.map    17.2 kB       0  [emitted]  main
polyfills.js.map     353 kB       1  [emitted]  polyfills
   vendor.js.map    3.94 MB       2  [emitted]  vendor
      index.html  607 bytes          [emitted]
    + 912 hidden modules

ERROR in ./src/client/app/app.component.ts
Module not found: Error: Cannot resolve 'file' or 'directory' ./app/app.component.html in C:\Users\markk\IdeaProjects\QuestionarySample2\src\client\app
 @ ./src/client/app/app.component.ts 18:22-57

...
Child html-webpack-plugin for "index.html":
        + 1 hidden modules

C:\Users\markk\IdeaProjects\QuestionarySample2>

(其他组件类似错误较多,我用省略号代替)

加载器将上述源代码转换为:

import { Component } from "@angular/core";

@Component({
    selector: 'app-root',
    template: require('./app/app.component.html')
})
export class AppComponent {
}

现在它失败了。

据我了解,原因是 require 在当前目录下工作,而 templateUrl 是相对于根目录的。因此,'./app/app.component.html' 在相对于根时是正确的,但在相对于当前位置时是错误的。

值得注意的是,我在源代码的任何地方都没有使用require,只有ES6 import语句,这也是相对于当前位置的。只有 Angular2 templateUrlstyleUrls 是相对于根的。

无论如何,我一定做错了什么,因为似乎没有人有我的问题。但是我做错了什么?

文件名为src/client/app/app.component.ts。源码目录结构为:

C:.
│   .gitignore
│   karma.conf.js
│   package.json
│   tsconfig.json
│   tslint.json
│   typings.json
│   webpack.config.js
│           
├───config
│       karma-test-shim.js
│       karma.conf.js
│       webpack.common.js
│       webpack.dev.js
│       webpack.prod.js
│       webpack.scratch.js
│       webpack.test.js
│       
└───src
    ├───client
    │   │   global.css
    │   │   index.html
    │   │   main.ts
    │   │   polyfills.ts
    │   │   tsconfig.json
    │   │   vendor.ts
    │   │   
    │   └───app
    │       │   app.component.html
    │       │   app.component.ts
    │       │   app.module.ts
    │       │   app.routing.ts
    │       │   settings.component.ts
    │       │   signout.component.ts
    │       │   
    │       ├───assets
    │       │       ...
    │       │       
    │       ├───questionnaire
    │       │       ...
    │       │       
    │       └───shared
    │               ...
    │               
    └───server
            api.ts
            main.ts
            tsconfig.json         

webpack 配置为:

webpack.config.js

module.exports = require('./config/webpack.dev.js'); 

./config/webpack.dev.js

var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
const path = require('path');

module.exports = webpackMerge(commonConfig, {
    // devtool: 'cheap-module-eval-source-map',
    devtool: 'source-map',

    output: {
        publicPath: `http://localhost:${commonConfig.port}/`,
        filename: '[name].js',
        sourceMapFilename: '[name].js.map',
        chunkFilename: '[id].chunk.js'
    },

    plugins: [
        new ExtractTextPlugin('[name].css')
    ],

    devServer: {
        inline: true,
        hot: true,
        progress: true,
        port: commonConfig.port,
        proxy: {
            '/api*': {
                target: `http://localhost:${commonConfig.port - 1}`
            }
        },
        historyApiFallback: true,
        watchOptions: {
            aggregateTimeout: 300,
            poll: 1000
        }
    }
});

./config/webpack.common.js

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');

module.exports = {
    port: process.env.PORT || 3000,

    entry: {
        polyfills: './src/client/polyfills',
        vendor: './src/client/vendor',
        main: './src/client/main'
    },

    output: {
        path: path.join(__dirname, '../dist/client'),
    },

    resolve: {
        extensions: ['', '.js', '.ts']
    },

    module: {
        loaders: [
            {
                test: /\.ts$/,
                loaders: ['ts', 'angular2-template-loader']
            },
            {
                test: /\.html$/,
                // loader: 'html'
                loader: 'raw'
            },
            {
                test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
                loader: 'file?name=assets/[name].[hash].[ext]'
            },
            // {
            //     test: /\.css$/,
            //     exclude: path.join(__dirname, '../src/client/app'),
            //     loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
            // },
            {
                test: /\.css$/,
                // exclude: path.join(__dirname, '../src/client/app'),
                loader: 'raw'
            }
        ]
    },

    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ['main', 'vendor', 'polyfills']
        }),

        new HtmlWebpackPlugin({
            template: 'src/client/index.html'
        })
    ]
};

我已经打开了一个问题,但我认为这只是我误解了 - https://github.com/TheLarkInn/angular2-template-loader/issues/20

编辑 1

伙计们,在建议改变之前

templateUrl: './app/app.component.html'

templateUrl: './app.component.html'

请阅读 Angular2 文档。特别是 https://angular.io/docs/ts/latest/guide/architecture.html 并查找文本 app/hero-list.component.ts (metadata)。它只有一次出现:

注意文件 app/hero-list.component.ts 引用了模板 app/hero-list.component.html。引用是相对于,而不是当前位置。

另外,我已经提到代码在没有加载器和“./app/app.component.html”路径的情况下工作正常。

我不知道,这可能是 Angular2 RC 之一的重大变化。但这是目前的情况。

【问题讨论】:

  • 只使用 templateUrl: 'app.component.html'
  • 为什么会起作用? Angular2 文档对此毫不含糊 - url 是相对于根的。但我还是检查了它,正如预期的那样,它不起作用。

标签: angular webpack


【解决方案1】:

它与 angular2-template-loader 无关,错误来自 webpack,而它无法找到您需要的文件

angular2-template-loader 是什么?

angular2-template-loader 在 Angular 2 组件元数据中搜索 templateUrl 和 styleUrls 声明,并用相应的 require 语句替换路径。

生成的 require 语句将由 .html 和 .js 文件的给定加载器处理。

如果您转到构建文件并搜索您的 AppComponent,您会发现 angular2-template-loader 已将 templateUrl: "path" 转换为 templateUrl: require("path")

这个

@Component({
    selector: 'app-root',
    templateUrl: './app/app.component.html'
})

应该是

@Component({
    moduleId: module.id, //not for webpack
    selector: 'app-root',
    templateUrl: './app.component.html'
})

在 @Component 装饰器中设置 moduleId: module.id 是这里的关键。如果你没有,那么 Angular 2 将在根级别查找你的文件。

Webpack 开发人员可以替代 moduleId。 他们可以在运行时加载模板和样式,方法是在模板的开头添加 ./ 和引用 *component-relative URLS 的样式/styleUrls 属性。

Question on Stackoverflow

Angular Docs

─app
    │   app.component.html--->same folder
    │   app.component.ts---->same folder
    │   app.module.ts
    │   app.routing.ts
    │   settings.component.ts
    │   signout.component.ts

当您询问templateUrl: './app/app.component.html' 时,它正在寻找当前目录中不存在的应用程序文件夹,您会收到错误消息。

【讨论】:

  • 我猜架构是建立在 SystemJS 之上的,而你使用的是 webpack,这是一个很大的不同。
  • 没有加载器也可以正常工作。我知道require 使用当前位置,但是无论加载器如何,Angular2 的 templateUrl 都是相对于根进行解析的,因为这是由 Angular2 本身完成的。我的代码不使用 SystemJS,我使用 webpack,但没有这个特定的加载器也能正常工作,因为我不使用 require。但是我已经在帖子里解释过了。我想知道如何在不更改代码的情况下使用加载器,因为如果我这样做,它将与那个特定的加载器耦合。现在不是,我想保持这种状态。
  • 我唯一的解释是在你去绝对路径之前,现在你正在使用 angular2-template-loader 将它转换为 require 然后 webpack 想要在 bundle 中构建它,但它不能解决它。我猜你之前没有在你的构建中捆绑 Html,现在它呢?
  • 我从未使用过绝对路径。原代码指的是'./app/app.component.html'。我之前没有在我的代码中捆绑 html,这是正确的。这是我第一次尝试这样做,但它不起作用。
  • 请注意:此答案中找到的两个链接现在都已损坏
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
相关资源
最近更新 更多