如何在Angular + Webpack + Heroku应用程序中加载App之前包含CSS

NCo*_*ley 5 css assets heroku webpack angular

我目前有一个使用webpack的Angular(v4.0.1)应用程序并部署到Heroku.我有一个加载微调器设置为在应用程序加载时显示在页面上.目前我已将其设置为本地工作,但出于某种原因,当我部署到heroku时,加载微调器(或更确切地说是用于旋转加载微调器的CSS)似乎不会被拉入.

我已经尝试了一些可能的修复但是我很难搞清楚我需要改变什么来让它在生产中工作,我在stackoverflow上发现的一切似乎只能在本地工作.我还应该澄清一下,应用程序中的所有css文件(如在应用程序加载后加载的组件样式)工作正常,它只是我在index.html中包含的一个css文件,专门用于加载微调器在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
Run Code Online (Sandbox Code Playgroud)

我的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>
Run Code Online (Sandbox Code Playgroud)

loading-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;
}
Run Code Online (Sandbox Code Playgroud)

我的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'
    })
  ]
};
Run Code Online (Sandbox Code Playgroud)

我的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'
  }
});
Run Code Online (Sandbox Code Playgroud)

我的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
      }
    })
  ]
});
Run Code Online (Sandbox Code Playgroud)

同样,一旦应用程序加载,我的所有资产(其他样式表,图标文件夹下的图像)都可以正常加载,因为我的webpack.common.js中的各种css和文件加载器正在正确处理它们.我假设这个问题与我的webpack.prod.js文件有关,因为所有这些都在本地工作,但我尝试的一切似乎都没有解决问题,loading-spinner.css文件根本没有被加载.任何意见,将不胜感激.

Pau*_*tha 3

从您的配置来看,您似乎只是逐字遵循了 webpack 上的 Angular 文档。在这些文档中,他们使用了全局样式表src/assets/css/styles.css。他们将其导入到AppComponent

import '../assets/css/styles.css';

@Component({
})
export class AppComponent { }
Run Code Online (Sandbox Code Playgroud)

这将导致从您或的ExtractTextPlugin(在本例中为 css)文件中提取文本,将其放入文件中,然后将该文件添加为. 输出文件名与实际文件名没有关联。恰好是为 .config 配置的名称。importrequirestyles.css<link>styles.cssExtractTextPlugin

如果您检查该dist文件夹并查看index.html,您将看到该styles.[hash].css文件被添加为<link>.

话虽如此,您应该对加载器 css 执行相同的操作。只需将其导入到AppComponent. 这将导致加载器将 css内容写入styles.[hash].css. 如果您想让加载器 css 与其他全局样式分开,请再考虑一下,因为这并不重要。无论如何,在加载所有样式表之前,浏览器不会开始渲染。

它适用于开发服务器的原因是因为开发服务器的工作方式略有不同。它配置为添加服务器的公共路径,可以从某个位置提供文件。

在这种情况下,可以从服务器访问资产。但是当您为生产而构建时,这些资产不会转移。它们需要导入到某个地方,因为这就是 webpack 在大多数端口上的工作方式。通过导入,webpack 知道它是一个应该构建用于分发的模块。

您也不需要index.html像您所做的那样手动添加加载器 css。只需导入它即可用于开发和生产。另外,您不需要在任何地方导入 svg,因为 webpack 已经在 loader css url 中检测到它,并将其传输到生产版本中