Ответ 1
Это один из недостатков использования ExtractTextPlugin
, как указано в README проекта. Вы можете решить проблему, разделив конфигурацию. То есть. имеют отдельную конфигурацию для разработки без нее и одну для производства с ней.
До сих пор я использовал функцию livereload, так что всякий раз, когда я меняю JS или шаблоны, страница обновляется, и когда я меняю CSS, это будет hotswap новый CSS без обновления.
Сейчас я тестирую webpack и почти добрался до одного и того же поведения, за одним исключением: при изменении CSS он обновляет все окно. Возможно ли сделать это hotswap CSS без обновления?
Конфигурация до сих пор:
var webpackConfig = {
entry: ["webpack/hot/dev-server", __dirname + '/app/scripts/app.js'],
debug: true,
output: {
path: __dirname + '/app',
filename: 'scripts/build.js'
},
devtool: 'source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(),
new htmlWebpackPlugin({
template: __dirname + '/app/index.html',
inject: 'body',
hash: true,
config: config
}),
new webpack.ProvidePlugin({
'angular': 'angular'
}),
new ExtractTextPlugin("styles.css")
],
module: {
loaders: [
{
test: /\.scss$/,
loader: "style!css!sass?includePaths[]=" + __dirname + "/app/bower_components/compass-mixins/lib&includePaths[]=" + __dirname + '/instance/sth/styles&includePaths[]=' + __dirname + '/app/scripts'
}
]
}
};
Это один из недостатков использования ExtractTextPlugin
, как указано в README проекта. Вы можете решить проблему, разделив конфигурацию. То есть. имеют отдельную конфигурацию для разработки без нее и одну для производства с ней.
Теперь можно использовать angular2, webpack с горячей заменой модуля, sass sourcemaps и загружаемый извне css. Мне понадобилось несколько дней, чтобы играть с ним, но я получил работу!
Зависимости style-loader
, css-loader
и sass-loader
(при использовании sass, если нет, загрузчик sass можно удалить)
Я использую ExtractTextPlugin для режима производства, чтобы испускать фактические .css файлы.
ПРИМЕЧАНИЕ. Чтобы это сработало, я не использую свойство stylesUrl, вместо этого я импортирую файл .scss за пределы декоратора @Component, чтобы стили загружались в глобальном контексте, а не в области с помощью компонента.
Эта конфигурация позволяет заменять Hot Module с помощью файлов SCSS с помощью сервера webpack dev и extracttextplugin для режима производства для извлечения фактических файлов .css.
Здесь моя рабочая конфигурация
{
test: /\.(scss)$/,
use:
isDevServer ? [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: { sourceMap: true }
},
{
loader: 'postcss-loader',
options: { postcss: [AutoPrefixer(autoPrefixerOptions)], sourceMap: true }
},
{
loader: 'sass-loader',
options: { sourceMap: true }
},
{
loader: 'sass-resources-loader',
options: {
resources: [
'./src/assets/styles/variables.scss',
'./src/assets/styles/mixins.scss']
}
},
/**
* The sass-vars-loader will convert the 'vars' property or any module.exports of
* a .JS or .JSON file into valid SASS and append to the beginning of each
* .scss file loaded.
*
* See: https://github.com/epegzz/sass-vars-loader
*/
{
loader: '@epegzz/sass-vars-loader?',
options: querystring.stringify({
vars: JSON.stringify({
susyIsDevServer: susyIsDevServer
})
})
}] : // dev mode
ExtractTextPlugin.extract({
fallback: "css-loader",
use: [
{
loader: 'css-loader',
options: { sourceMap: true }
},
{
loader: 'postcss-loader',
options: { postcss: [AutoPrefixer(autoPrefixerOptions)], sourceMap: true }
},
{
loader: 'sass-loader',
options: { sourceMap: true }
},
{
loader: 'sass-resources-loader',
options: {
resources: [
'./src/assets/styles/variables.scss',
'./src/assets/styles/mixins.scss']
}
}, {
loader: '@epegzz/sass-vars-loader?',
options: querystring.stringify({
vars: JSON.stringify({
susyIsDevServer: susyIsDevServer
})
// // Or use 'files" object to specify vars in an external .js or .json file
// files: [
// path.resolve(helpers.paths.appRoot + '/assets/styles/sass-js-variables.js')
// ],
})
}],
publicPath: '/' // 'string' override the publicPath setting for this loader
})
},
Затем в вашем компоненте, например, app.component.ts
, вам понадобится файл app.style.scss
ВНЕШНЕГО декодера @Component.
Это трюк. Это не будет работать, если вы загрузите стили "angular" с помощью stylesUrl
. Выполнение этого способа позволит вам ленить нагрузку .css
таблиц стилей для компонентов, которые ленивы загружены, что делает начальное время загрузки еще быстрее.
app.component.css
/*
* THIS IS WHERE WE REQUIRE CSS/SCSS FILES THAT THIS COMPONENT NEEDS
*
* Function: To enable so-called "Lazy Loading" CSS/SCSS files "on demand" as the app views need them.
* Do NOT add styles the "Angular2 Way" in the @Component decorator ("styles" and "styleUrls" properties)
*/
import './app.style.scss'
/**
* AppComponent Component
* Top Level Component
*/
@Component({
selector: 'body',
encapsulation: ViewEncapsulation.None,
host: { '[class.authenticated]': 'appState.state.isAuthenticated' },
templateUrl: './app.template.html'
})
У меня не было проблем с этой настройкой. Здесь вы идете!
Обновлено 08/2017: Улучшена конфигурация для требований к схеме webpack 3+ и для работы с Angular 4 компиляцией AOT.
На самом деле это простой способ сделать это. Я использую sass-loader с extract-text-plugin, который создает css файлы.
Что вам нужно сделать, это добавить id в ваш css include
<link id="js-style" type="text/css" rel="stylesheet" href="/static/main.css">
Теперь вам нужно убедиться, что когда HMR происходит, вы обновляете url с текущей версией/меткой времени. Вы можете сделать это следующим образом:
import '../style/main.scss'
if (module.hot) {
module.hot.accept('../style/main.scss', () => {
const baseStyle = window.document.getElementById('js-style')
baseStyle.setAttribute('href', '/static/main.css?v=' + new Date().valueOf)
})
}
Таким образом, всякий раз, когда изменяется css, мы исправляем URL-адрес css include, чтобы перезагрузить его.
Хотя ExtractTextPlugin заявляет "No Hot Module Replacement" в разделе README, Я исправил это, вручную обновив файлы CSS через API BrowserSync.
Я использовал gaze для прослушивания любых изменений в моих файлах CSS, а затем использовал BrowserSync для их обновления.
npm install gaze
Вы также можете легко сделать это, отредактировав свою сборку script следующим образом:
const { Gaze } = require('gaze');
// Your own BrowserSync init
browserSync.init({
...
}, resolve);
// Create a watcher:
// You can watch/reload specific files according to your build/project structure
const gaze = new Gaze('**/*.css');
gaze.on('all', () => bs.reload('*.css'));
Надеюсь, что это поможет.