#angular #webpack
#angular #webpack
Вопрос:
Я использую плагин html-webpack-plugin для вставки <script>
тегов в файл шаблона для фрагментов, которые генерирует webpack. У меня также есть несколько глобальных таблиц стилей, которые я хочу динамически добавлять в <head>
раздел моего HTML-шаблона. Для этого я также использую 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 выполняет поиск объявлений templateUrl и styleUrls внутри метаданных компонента Angular 2 и заменяет пути соответствующим оператором require.
Проблема заключается в том, что помимо двух таблиц стилей, которые добавляются в точку app.ts
входа, webpack также включает в себя все таблицы стилей, на которые ссылаются мои компоненты Angular2. Потому что он просматривает зависимости приложения и находит require
инструкции, добавленные angular2-template-loader. Это нежелательно, потому что я хочу, чтобы эти таблицы стилей были локальными для компонентов, которым они принадлежат, т. Е. Были встроенными в JS.
Поэтому мне нужен способ включать только те таблицы стилей, которые я require
использую непосредственно в своих точках входа, возможно, каким-то образом исключая таблицы стилей компонентов. Проблема в том, что в обоих случаях файл имеет .css
расширение, поэтому они оба проходят тест на extract-text-plugin
. Я просмотрел документацию загрузчиков / плагинов, но не смог найти ничего, что решило бы мою проблему.
Итак, я хочу добавить app.[contenthash].css
файл в мой файл шаблона (эта часть работает), но исключая таблицы стилей, на которые ссылаются в моих компонентах Angular2 (включены из-за angular2-template-loader).
Как я могу предотвратить включение этих таблиц стилей компонента Angular2 в таблицу стилей, добавляемую в мой HTML-шаблон?
Ответ №1:
Допустим, у вас следующая структура папок:
Итак, все мои компоненты расположены внутри папки приложения.
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. Ах, это выглядит довольно хорошо! Я как можно скорее проверю это и сообщу вам, как это происходит. Спасибо!
2. Я попытался поиграть с этим, но не смог заставить его работать. Прежде всего, мои CSS-файлы расположены по адресу
public/css
, где расположены таблицы стилей для компонентовpublic/css/components/**/*.css
. Я попытался исключить/public/css/components/
в первом загрузчике и использовалraw
для второго, наряду с множеством различных тестов и исключений, с различными ошибками. Я не уверен, что я путаюсь с путями / регулярным выражением или в чем проблема. Если бы вы могли привести пример с вышеупомянутыми путями, это было бы действительно здорово, потому что я, похоже, не могу заставить его работать.3. Попробуйте
/public\css\components/
или/css\components/
4. После опробования тонны комбинаций мне удалось заставить его работать. Хотя я не добился успеха именно с тем, что вы предложили, это было достаточно близко, чтобы направить меня на правильный путь, так что большое спасибо за это! Я добавил ответ с моим решением для всех, кому это может понадобиться. Приветствия!
Ответ №2:
Вы могли бы дать webpack подсказку, чтобы различать файлы CSS, используя два отдельных шаблона имен. Допустим, вы называете все файлы, которые должны быть включены в angular2-template-loader, с помощью суффикса .tl
(сокращение от template loader, например mycss.tl.css
), а другие — с помощью суффикса .pt
(сокращение от platform, например 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 по-прежнему обертывает пути css require
вызовами, но в зависимости от вашей конфигурации у вас может быть другой набор загрузчиков для файлов css.
Комментарии:
1. На самом деле я думал о том, чтобы сделать что-то подобное, но мне это показалось взломом, поэтому я подумал, есть ли лучшее решение. Я немного поиграю с этим и посмотрю, что я могу придумать. Спасибо за ваш ответ! 🙂
Ответ №3:
Для всех, кому интересно, мне удалось решить проблему, вдохновленный ответом @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');
Я надеюсь, что это кому-то поможет.