在webpack

时间:2016-10-06 19:25:04

标签: angular webpack

我正在使用html-webpack-plugin插件将<script>标记注入到webpack生成的块的模板文件中。我还有一些全局样式表,我想动态添加到HTML模板的<head>部分。为此,我也使用html-webpack-plugin如下(在这种情况下,app条目/块是相关的。)

module.exports = {
    entry: {
        'polyfills': './ts/polyfills.ts',
        'vendor': './ts/vendor.ts',
        'app': './ts/app.ts'
    },

    module: {
        loaders: [
            {
                test: /\.ts$/,
                loaders: ['ts', 'angular2-template-loader']
            },
            {
                test: /\.html$/,
                loader: 'html-loader'
            },
            {
                test: /\.css$/,
                loaders: ['to-string-loader', ExtractTextPlugin.extract('style-loader', 'css-loader')]
            }
        ]
    },

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

        new webpack.ProvidePlugin({
            bootstrap: 'bootstrap'
        }),

        new webpack.optimize.CommonsChunkPlugin({
            name: 'app',
            filename: 'js/[name].[chunkhash].min.js',
            chunks: ['app']
        }),

        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            filename: 'js/[name].[chunkhash].min.js',
            chunks: ['vendor']
        }),

        new webpack.optimize.CommonsChunkPlugin({
            name: 'polyfills',
            filename: 'js/[name].[chunkhash].min.js',
            chunks: ['polyfills']
        }),

        new HtmlWebpackPlugin({
            template: 'my-template.html',
            filename: 'my-template.html',
            inject: 'body',
            hash: false
        }),
    ]
};

下面是app.ts文件,其中我为每个样式表添加了require语句,我希望将其包含在我的模板中(它们被合并到一个样式表中)。

require('main.css');
require('misc.css');

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

基本上这很好用,但问题是我将这个配置用于Angular2应用程序,该应用程序由可能具有关联样式表的组件组成,如本例所示。

@Component({
    styleUrls: [
        'my-stylesheet.css'
    ]
})
export class MyComponent { ... }

构建应用程序通常会导致对组件的这些样式表进行大量的HTTP调用,因此要解决此问题,我已使用angular2-template-loader将样式表直接拖到组件中。这个加载器的工作原理如下。

  

angular2-template-loader搜索templateUrl和styleUrls   Angular 2 Component元数据中的声明并替换   带有相应require语句的路径。

问题在于,除了添加到app.ts入口点的两个样式表之外,webpack还包括从我的Angular2组件引用的每个样式表。因为它遍历应用程序的依赖项并找到由angular2-template-loader添加的require语句。这是不可取的,因为我希望这些样式表对于它们所属的组件是本地的,即在JS中内联。

因此,我需要一种方法 直接在我的入口点中包含我require的样式表,可能以某种方式排除组件样式表。问题是,在这两种情况下,文件都有.css扩展名,因此它们都通过了extract-text-plugin的测试。我看了一下加载器/插件的文档,但我找不到能解决问题的东西。

所以我想要的是将app.[contenthash].css文件添加到我的模板文件中(这部分有效),但不包括我的Angular2组件中引用的样式表(因为angular2-template而包含) -loader)。

如何防止这些Angular2组件样式表包含在添加到HTML模板的样式表中?

3 个答案:

答案 0 :(得分:5)

假设您有以下文件夹结构:

enter image description here

所以我的所有组件都位于 app 文件夹中。

<强> main.ts

require('main.css');
require('misc.css');

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

<强> /app/app.component.ts

@Component({
  selector: 'my-app',
  template: `<h1>My Angular 2 App</h1>`,
  styleUrls: ['my-stylesheet.css']
})
export class AppComponent {}

然后您的解决方案可能如下:

<强> webpack.config.js

{
  test: /\.css$/,
  exclude: /app\\.+\.css$/, <== add this (exclude all styles from app folder)
  loaders: ['to-string-loader', ExtractTextPlugin.extract('style-loader', 'css-loader')]
},
{
  test: /app\\.+\.css$/,
  loader: 'raw'  <== use raw loader for these files
}

答案 1 :(得分:1)

您可以通过使用两个单独的名称模式为webpack提供一个提示来区分CSS文件。假设您将angular2-template-loader应包含的所有文件命名为后缀.tl(模板加载器的缩写,例如mycss.tl.css),其他的后缀为.pt(平台的缩写) ,例如main.pt.css),然后您可以按如下方式编写webpack配置:

module: {
        loaders: [
            {
                test: /\.ts$/,
                loaders: ['ts', 'angular2-template-loader']
            },
            {
                test: /\.pt\.css$/,
                loaders: ['to-string-loader', ExtractTextPlugin.extract('style-loader', 'css-loader')]
            },
            {
                test: /\.tl\.css$/,
                loaders: ['style-loader', 'css-loader']
            }
        ]
    }

您的组件定义如下所示

@Component({
    styleUrls: [
        'my-stylesheet.tl.css'
    ]
})
export class MyComponent { ... }

而在app.ts你放置

require('main.pt.css');
require('misc.pt.css');

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

angular2-template-loader然后仍然使用require调用包装css路径,但根据您的配置,您可以为css文件设置一组不同的加载器。

答案 2 :(得分:0)

对于任何有兴趣的人,我确实设法解决了这个问题,受到@ yurzui的回答的启发。

module: {
    loaders: [
        {
            test: /\.ts$/,
            loaders: ['ts', 'angular2-template-loader']
        },
        {
            test: /\.css$/,
            exclude: [helpers.root('public', 'css', 'components')],
            loaders: ['to-string-loader', ExtractTextPlugin.extract('style-loader', 'css-loader')]
        },
        {
            test: /\.css$/,
            include: [helpers.root('public', 'css', 'components')],
            loaders: ['raw-loader']
        }
    ]
}

在上面的例子中,我使用我的自定义帮助程序来组装目录的路径。你可以用其他方式做到这一点,但无论如何这里都是我的助手(摘自Angular2的文档)。

var path = require('path');
var _root = path.resolve(__dirname, '..'); // This file is stored within a webpack subdirectory in my case

function root(args) {
    args = Array.prototype.slice.call(arguments, 0);
    return path.join.apply(path, [_root].concat(args));
}

exports.root = root;

要使用它,只需在webpack配置中使用它。

var helpers = require('./helpers');

我希望这有助于某人。