如何在 Angular + Webpack + Heroku 应用程序加载应用程序之前包含 CSS
How To Include CSS Before App Load in Angular + Webpack + Heroku Application
我目前有一个使用 webpack 并部署到 Heroku 的 Angular (v4.0.1) 应用程序。我有一个加载微调器设置为在应用程序加载时显示在页面上。目前我已经设置它以便它在本地工作,但是由于某种原因当我部署到 heroku 时加载微调器(或者更具体地说 CSS 来旋转加载微调器)似乎没有被拉入。
我已经尝试了一些可能的修复,但我很难弄清楚我需要更改什么才能让它在生产中工作,而我在 Whosebug 上找到的所有内容似乎只能在本地工作。我还应该澄清,我在应用程序中的所有 css 文件(如在应用程序加载后加载的组件样式中)工作正常,它只是我包含在index.html 专门用于在 Angular 应用程序加载之前需要可用的加载微调器。
我的文件结构(简化):
.
+-- config/
+-- src/
| +-- app/
| +-- assets/
| +-- icons/
| +-- loading-spinner.svg
| +-- stylesheets/
| +--- loading-spinner.css
| +-- vendor/
| +-- index.html
| +-- main.ts
| +-- polyfills.ts
| +-- tsconfig.json
+-- package.json
+-- server.js
我的index.html
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>Stylist Suite 2.0</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="src/assets/stylesheets/loading-spinner.css">
</head>
<body>
<ss-app>
<div class="loading-spinner ss-loading"></div>
</ss-app>
</body>
</html>
正在加载-spinner.css文件:
/* --- Loading Spinner - Needed Before App Loads ---*/
.loading-spinner {
width: 42px;
height: 44px;
background: url("../icons/loading-spinner.svg") no-repeat;
margin: 0 auto;
animation: spin 2.5s linear infinite;
-webkit-animation: spin 2.5s linear infinite;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-spinner .ss-loading {
position: fixed;
top:50%;
left:50%;
margin-left:-21px;
margin-top: -22px;
align-self: center;
justify-self: center;
}
我的webpack.common.js(位于config/下)
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var helpers = require('./helpers');
module.exports = {
entry: {
'polyfills': './src/polyfills.ts',
'vendor': './src/vendor/vendor.ts',
'app': './src/main.ts'
},
resolve: {
extensions: ['.ts', '.js']
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file-loader?name=assets/[name].[hash].[ext]'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract({ loader: 'style-loader', use: 'css-loader?sourceMap' })
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw-loader'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'assets'),
loader: ExtractTextPlugin.extract({ loader: 'style-loader', use: 'css-loader?sourceMap' })
},
{
test: /\.css$/,
include: helpers.root('src', 'assets'),
loader: 'raw-loader'
},
{
test: /\.scss$/,
exclude: /node_modules/,
loaders: ['to-string-loader', 'style-loader', 'css-loader', 'resolve-url-loader', 'sass-loader?sourceMap']
},
{
test: /\.ts$/,
loaders: [
{
loader: 'awesome-typescript-loader',
options: { configFileName: helpers.root('src', 'tsconfig.json') }
}, 'angular2-template-loader'
]
}
]
},
plugins: [
// Workaround for angular/angular#11580
new webpack.ContextReplacementPlugin(
// The (\|\/) piece accounts for path separators in *nix and Windows
/angular(\|\/)core(\|\/)(esm(\|\/)src|src)(\|\/)linker/,
helpers.root('./src'), // location of your src
{} // a map of your routes
),
new webpack.optimize.CommonsChunkPlugin({
name: ['app', 'vendor', 'polyfills']
}),
new HtmlWebpackPlugin({
template: 'src/index.html'
})
]
};
我的webpack.dev.js(位于config/下)
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var helpers = require('./helpers');
module.exports = webpackMerge(commonConfig, {
devtool: 'cheap-module-eval-source-map',
output: {
path: helpers.root('dist'),
publicPath: 'http://localhost:4200/',
filename: '[name].js',
chunkFilename: '[id].chunk.js'
},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.DefinePlugin({
'process.env.API_APPLICATION_ID': JSON.stringify(""),
'process.env.REDIRECT_URL': JSON.stringify("http://localhost:4200/login"),
'process.env.API_BASE_URL': JSON.stringify("http://localhost:3000"),
'process.env.SITE_URL': JSON.stringify("http://localhost:3000")
})
],
devServer: {
historyApiFallback: true,
stats: 'minimal'
}
});
我的webpack.prod.js(位于config/下)
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var helpers = require('./helpers');
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
module.exports = webpackMerge(commonConfig, {
devtool: 'source-map',
output: {
path: helpers.root('dist'),
publicPath: '/',
filename: '[name].[hash].js',
chunkFilename: '[id].[hash].chunk.js'
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618
mangle: {
keep_fnames: true
}
}),
new ExtractTextPlugin('[name].[hash].css'),
new webpack.DefinePlugin({
'process.env.API_APPLICATION_ID': JSON.stringify(process.env.API_APPLICATION_ID),
'process.env.REDIRECT_URL': JSON.stringify(process.env.REDIRECT_URL),
'process.env.API_BASE_URL': JSON.stringify(process.env.API_BASE_URL),
'process.env.SITE_URL': JSON.stringify(process.env.REDIRECT_URL)
}),
new webpack.LoaderOptionsPlugin({
htmlLoader: {
minimize: false // workaround for ng2
}
})
]
});
同样,我的所有资产(其他样式表、图标文件夹下的图像)在应用程序加载后都可以正常加载,因为我的 css 中的各种 css 和文件加载器正在正确处理它们=39=].我假设问题与我的 webpack.prod.js 文件有关,因为所有这些都在本地完美运行,但我尝试的一切似乎根本无法解决问题,loading-spinner.css 文件未加载全部。如有任何建议,我们将不胜感激。
从您的配置来看,您似乎只是逐字地遵循了 Angular docs on webpack。在这些文档中,他们使用了全局样式表 src/assets/css/styles.css
。他们将其导入 AppComponent
import '../assets/css/styles.css';
@Component({
})
export class AppComponent { }
这将导致 ExtractTextPlugin
从您 import
或 require
的文件(在本例中为 css)中提取文本,将其放入在 styles.css
文件中,并将该文件添加为 <link>
。输出文件名与实际文件名没有关联。 styles.css
恰好是为 ExtractTextPlugin
配置的名称。
如果您检查 dist
文件夹,然后检查 index.html
,您会看到此 styles.[hash].css
文件被添加为 <link>
.
也就是说,您应该对加载程序执行相同的操作 css。只需将其导入 AppComponent
。这会导致loader css content 变成styles.[hash].css
。如果你想让加载器 css 与其他全局样式分开,请再考虑一下,因为这并不重要。在加载所有样式表之前,浏览器不会开始呈现。
它适用于开发服务器的原因是因为开发服务器的工作方式略有不同。它被配置为为服务器添加一个 public 路径,它可以从一个位置提供文件。
在这种情况下,可以从服务器访问资产。但是当您为生产而构建时,这些资产不会转移。它们需要在某个地方导入,因为这是 webpack 在大多数端口上的工作方式。通过导入,webpack 知道它是一个应该构建用于分发的模块。
您也不需要手动将加载程序 css 添加到 index.html
,就像您所做的那样。只需导入它,它就可以同时用于开发和生产。此外,您不需要在任何地方导入 svg,因为 webpack 已经在加载器 css url 中检测到它,并在生产构建中传输它
我目前有一个使用 webpack 并部署到 Heroku 的 Angular (v4.0.1) 应用程序。我有一个加载微调器设置为在应用程序加载时显示在页面上。目前我已经设置它以便它在本地工作,但是由于某种原因当我部署到 heroku 时加载微调器(或者更具体地说 CSS 来旋转加载微调器)似乎没有被拉入。
我已经尝试了一些可能的修复,但我很难弄清楚我需要更改什么才能让它在生产中工作,而我在 Whosebug 上找到的所有内容似乎只能在本地工作。我还应该澄清,我在应用程序中的所有 css 文件(如在应用程序加载后加载的组件样式中)工作正常,它只是我包含在index.html 专门用于在 Angular 应用程序加载之前需要可用的加载微调器。
我的文件结构(简化):
.
+-- config/
+-- src/
| +-- app/
| +-- assets/
| +-- icons/
| +-- loading-spinner.svg
| +-- stylesheets/
| +--- loading-spinner.css
| +-- vendor/
| +-- index.html
| +-- main.ts
| +-- polyfills.ts
| +-- tsconfig.json
+-- package.json
+-- server.js
我的index.html
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>Stylist Suite 2.0</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="src/assets/stylesheets/loading-spinner.css">
</head>
<body>
<ss-app>
<div class="loading-spinner ss-loading"></div>
</ss-app>
</body>
</html>
正在加载-spinner.css文件:
/* --- Loading Spinner - Needed Before App Loads ---*/
.loading-spinner {
width: 42px;
height: 44px;
background: url("../icons/loading-spinner.svg") no-repeat;
margin: 0 auto;
animation: spin 2.5s linear infinite;
-webkit-animation: spin 2.5s linear infinite;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-spinner .ss-loading {
position: fixed;
top:50%;
left:50%;
margin-left:-21px;
margin-top: -22px;
align-self: center;
justify-self: center;
}
我的webpack.common.js(位于config/下)
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var helpers = require('./helpers');
module.exports = {
entry: {
'polyfills': './src/polyfills.ts',
'vendor': './src/vendor/vendor.ts',
'app': './src/main.ts'
},
resolve: {
extensions: ['.ts', '.js']
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file-loader?name=assets/[name].[hash].[ext]'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract({ loader: 'style-loader', use: 'css-loader?sourceMap' })
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw-loader'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'assets'),
loader: ExtractTextPlugin.extract({ loader: 'style-loader', use: 'css-loader?sourceMap' })
},
{
test: /\.css$/,
include: helpers.root('src', 'assets'),
loader: 'raw-loader'
},
{
test: /\.scss$/,
exclude: /node_modules/,
loaders: ['to-string-loader', 'style-loader', 'css-loader', 'resolve-url-loader', 'sass-loader?sourceMap']
},
{
test: /\.ts$/,
loaders: [
{
loader: 'awesome-typescript-loader',
options: { configFileName: helpers.root('src', 'tsconfig.json') }
}, 'angular2-template-loader'
]
}
]
},
plugins: [
// Workaround for angular/angular#11580
new webpack.ContextReplacementPlugin(
// The (\|\/) piece accounts for path separators in *nix and Windows
/angular(\|\/)core(\|\/)(esm(\|\/)src|src)(\|\/)linker/,
helpers.root('./src'), // location of your src
{} // a map of your routes
),
new webpack.optimize.CommonsChunkPlugin({
name: ['app', 'vendor', 'polyfills']
}),
new HtmlWebpackPlugin({
template: 'src/index.html'
})
]
};
我的webpack.dev.js(位于config/下)
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var helpers = require('./helpers');
module.exports = webpackMerge(commonConfig, {
devtool: 'cheap-module-eval-source-map',
output: {
path: helpers.root('dist'),
publicPath: 'http://localhost:4200/',
filename: '[name].js',
chunkFilename: '[id].chunk.js'
},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.DefinePlugin({
'process.env.API_APPLICATION_ID': JSON.stringify(""),
'process.env.REDIRECT_URL': JSON.stringify("http://localhost:4200/login"),
'process.env.API_BASE_URL': JSON.stringify("http://localhost:3000"),
'process.env.SITE_URL': JSON.stringify("http://localhost:3000")
})
],
devServer: {
historyApiFallback: true,
stats: 'minimal'
}
});
我的webpack.prod.js(位于config/下)
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var helpers = require('./helpers');
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
module.exports = webpackMerge(commonConfig, {
devtool: 'source-map',
output: {
path: helpers.root('dist'),
publicPath: '/',
filename: '[name].[hash].js',
chunkFilename: '[id].[hash].chunk.js'
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618
mangle: {
keep_fnames: true
}
}),
new ExtractTextPlugin('[name].[hash].css'),
new webpack.DefinePlugin({
'process.env.API_APPLICATION_ID': JSON.stringify(process.env.API_APPLICATION_ID),
'process.env.REDIRECT_URL': JSON.stringify(process.env.REDIRECT_URL),
'process.env.API_BASE_URL': JSON.stringify(process.env.API_BASE_URL),
'process.env.SITE_URL': JSON.stringify(process.env.REDIRECT_URL)
}),
new webpack.LoaderOptionsPlugin({
htmlLoader: {
minimize: false // workaround for ng2
}
})
]
});
同样,我的所有资产(其他样式表、图标文件夹下的图像)在应用程序加载后都可以正常加载,因为我的 css 中的各种 css 和文件加载器正在正确处理它们=39=].我假设问题与我的 webpack.prod.js 文件有关,因为所有这些都在本地完美运行,但我尝试的一切似乎根本无法解决问题,loading-spinner.css 文件未加载全部。如有任何建议,我们将不胜感激。
从您的配置来看,您似乎只是逐字地遵循了 Angular docs on webpack。在这些文档中,他们使用了全局样式表 src/assets/css/styles.css
。他们将其导入 AppComponent
import '../assets/css/styles.css';
@Component({
})
export class AppComponent { }
这将导致 ExtractTextPlugin
从您 import
或 require
的文件(在本例中为 css)中提取文本,将其放入在 styles.css
文件中,并将该文件添加为 <link>
。输出文件名与实际文件名没有关联。 styles.css
恰好是为 ExtractTextPlugin
配置的名称。
如果您检查 dist
文件夹,然后检查 index.html
,您会看到此 styles.[hash].css
文件被添加为 <link>
.
也就是说,您应该对加载程序执行相同的操作 css。只需将其导入 AppComponent
。这会导致loader css content 变成styles.[hash].css
。如果你想让加载器 css 与其他全局样式分开,请再考虑一下,因为这并不重要。在加载所有样式表之前,浏览器不会开始呈现。
它适用于开发服务器的原因是因为开发服务器的工作方式略有不同。它被配置为为服务器添加一个 public 路径,它可以从一个位置提供文件。
在这种情况下,可以从服务器访问资产。但是当您为生产而构建时,这些资产不会转移。它们需要在某个地方导入,因为这是 webpack 在大多数端口上的工作方式。通过导入,webpack 知道它是一个应该构建用于分发的模块。
您也不需要手动将加载程序 css 添加到 index.html
,就像您所做的那样。只需导入它,它就可以同时用于开发和生产。此外,您不需要在任何地方导入 svg,因为 webpack 已经在加载器 css url 中检测到它,并在生产构建中传输它