2017-03-10 101 views
0

我目前正在開發一個Angular 2項目,並使用Webpack 2捆綁代碼和資產。 Angular應用程序使用Bootstrap和包含全局樣式的styles.css。Webpack - 如何配置Webpack以不同方式捆綁全局和模塊化CSS?

此外,Angular組件本身在獨立的.css文件中有自己的樣式表。請參閱下面的文件結構爲例:

app/index.html 
app/styles.css 
app/component/component.js 
app/component/component.html 
app/component/component.css 

目前,採取的WebPack所有這些文件都.css和.js文件的並將它們捆綁在一起,所以我有以下的輸出(CSS合併成JavaScript的):

dist/index.html 
dist/js/app.bundle.js 

我主要的問題是,這將創建一個FOUC(無樣式內容的閃存) - 從我的理解來解決它正在改變CSS代碼拆分輸出CSS到自己的文件,使其能方式通過瀏覽器異步加載 - 使用Extract-Text-Webpack-Plugin。

這工作很好,除了使用這種方法我留下了另一個問題。我輸了有模塊化的CSS角通過 component.css文件提供

所以我有以下2個問題的能力...:

1)我怎麼配置的WebPack只是提取Bootstrap和我的styles.css到例如「dist/styles.css」,但將其餘的「非全局」CSS文件捆綁爲Webpack創建的JavaScript捆綁包的一部分?

2.)是否可以將這個提取的CSS注入到index.html的HEAD部分,就像bundle正在通過HTML-webpack-plugin注入一樣?

new HtmlWebpackPlugin({ 
    filename: 'index.html', 
    inject: 'body', 
    template: 'ngApp/index.html' 
}) 

(這讓我不必硬編碼的href中指向輸出路徑,如果有人改變了的WebPack配置是可能會發生變化。)

我目前的解決方案到這個問題是使用copy-webpack-plugin來移動 bootstrap.min.css styles.css dist並在index.html中使用硬編碼鏈接 - 但我不喜歡這種設置。歡迎任何建議。

謝謝。

+0

如果我理解正確的,我試圖回答類似的問題[這裏](http://stackoverflow.com/questions/39698124/webpack-bundle-all-css -and-負載第一/ 43972645#43972645)。 我也在尋找更好的解決方案,但現在這個適合我。 –

回答

0

以防萬一這仍然是相關的: 我已經設法爲您的第一個問題找到解決方案,因爲我試圖爲Spring Boot應用程序構建一個Angular 4前端,並面對完全相同的問題。這裏是我的webpack.config.js:

// Helper: root() is defined at the bottom 
var path = require('path'); 
var webpack = require('webpack'); 

// Webpack Plugins 
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; 
var autoprefixer = require('autoprefixer'); 
var ExtractTextPlugin = require('extract-text-webpack-plugin'); 
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 

/** 
* Env 
* Get npm lifecycle event to identify the environment 
*/ 
var ENV = process.env.npm_lifecycle_event; 
var isProd = ENV === 'build'; 

module.exports = function makeWebpackConfig() { 
    /** 
    * Config 
    * Reference: http://webpack.github.io/docs/configuration.html 
    * This is the object where all configuration gets set 
    */ 
    var config = {}; 

    /** 
    * Devtool 
    * Reference: http://webpack.github.io/docs/configuration.html#devtool 
    * Type of sourcemap to use per build type 
    */ 
    if (isProd) { 
     config.devtool = 'source-map'; 
    } 
    else { 
     config.devtool = 'eval-source-map'; 
    } 

    /** 
    * Entry 
    * Reference: http://webpack.github.io/docs/configuration.html#entry 
    */ 
    config.entry = { 
     'polyfills': './src/main/frontend/polyfills.ts', 
     'vendor': './src/main/frontend/vendor.ts', 
     'style': './src/main/frontend/style/global.scss', // global styles 
     'app': './src/main/frontend/main.ts'    // angular app 
    }; 

    /** 
    * Output 
    * Reference: http://webpack.github.io/docs/configuration.html#output 
    */ 
    config.output = { 
     path: root('src/main/webapp'), 
     publicPath: isProd ? '/' : 'http://localhost:8080/', 
     filename: 'js/[name].js', 
     chunkFilename: '[id].chunk.js' 
    }; 

    /** 
    * Resolve 
    * Reference: http://webpack.github.io/docs/configuration.html#resolve 
    */ 
    config.resolve = { 
     // only discover files that have those extensions 
     extensions: ['.ts', '.js', '.json', '.css', '.scss', '.html'] 
    }; 

    /** 
    * Loaders 
    * Reference: http://webpack.github.io/docs/configuration.html#module-loaders 
    * List: http://webpack.github.io/docs/list-of-loaders.html 
    * This handles most of the magic responsible for converting modules 
    */ 
    config.module = { 
     rules: [ 

      // Support for .ts files. 
      { 
       test: /\.ts$/, 
       use: ['awesome-typescript-loader', 'angular2-template-loader', '@angularclass/hmr-loader', 'angular2-router-loader'], 
       exclude: [/\.(spec|e2e)\.ts$/, /node_modules\/(?!(ng2-.+))/] 
      }, 

      // copy those assets to output 
      { 
       test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/, 
       use: 'file-loader?name=fonts/[name].[ext]?' 
      }, 

      // Support for *.json files. 
      { 
       test: /\.json$/, 
       loader: 'json-loader' 
      }, 

      // build global css bundle from src/main/frontend/style/global.css 
      { 
       test: /global\.(css|scss)/, 
       use: ExtractTextPlugin.extract(['css-loader', 'sass-loader']) 
      }, 

      // all css required in src/main/frontend files will be merged in js files 
      { 
       test: /\.(css|scss|sass)$/, 
       loader: 'raw-loader!postcss-loader!sass-loader', 
       exclude: [/global\.(css|scss)/] 
      }, 

      // support for .html as raw text 
      // todo: change the loader to something that adds a hash to images 
      { 
       test: /\.html$/, 
       use: 'raw-loader' 
      } 
     ] 
    }; 

    /** 
    * Plugins 
    * Reference: http://webpack.github.io/docs/configuration.html#plugins 
    * List: http://webpack.github.io/docs/list-of-plugins.html 
    */ 
    config.plugins = [ 
     // Define env variables to help with builds 
     // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin 
     new webpack.DefinePlugin({ 
      // Environment helpers 
      'process.env': { 
       ENV: JSON.stringify(ENV) 
      } 
     }), 


     // Workaround needed for angular 2 angular/angular#11580 
     new webpack.ContextReplacementPlugin(
      // The (\\|\/) piece accounts for path separators in *nix and Windows 
      /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, 
      root('./src/main/frontend') // location of your src 
     ), 

     new webpack.LoaderOptionsPlugin({ 
      options: { 
       /** 
       * PostCSS 
       * Reference: https://github.com/postcss/autoprefixer-core 
       * Add vendor prefixes to your css 
       */ 
       postcss: [ 
        autoprefixer({ 
         browsers: ['last 2 version'] 
        }) 
       ] 
      } 
     }), 

     // Generate common chunks if necessary 
     // Reference: https://webpack.github.io/docs/code-splitting.html 
     // Reference: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin 
     new CommonsChunkPlugin({ 
      name: ['app', 'vendor', 'polyfills'] 
     }), 

     // Extract css files 
     // Reference: https://github.com/webpack/extract-text-webpack-plugin 
     // Disabled when in test mode or not in build mode 
     new ExtractTextPlugin({ 
      filename: 'css/[name].min.css' 
     }) 
    ]; 

    // Add build specific plugins 
    if (isProd) { 
     config.plugins.push(
      // Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin 
      // Only emit files when there are no errors 
      new webpack.NoEmitOnErrorsPlugin(), 

      // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 
      // Minify all javascript, switch loaders to minimizing mode 
      new webpack.optimize.UglifyJsPlugin({sourceMap: true, mangle: {keep_fnames: true}}), 


      // optimize CSS assets 
      // Reference: https://github.com/NMFR/optimize-css-assets-webpack-plugin 
      new OptimizeCssAssetsPlugin({ 
       assetNameRegExp: /\.css$/g, 
       cssProcessor: require('cssnano'), 
       cssProcessorOptions: { 
        discardComments: 
         { 
          removeAll: true 
         } 
       }, 
       canPrint: true 
      }), 

      // // Reference: https://github.com/webpack-contrib/webpack-bundle-analyzer 
      new BundleAnalyzerPlugin({ 
       // Can be `server`, `static` or `disabled`. 
       // In `server` mode analyzer will start HTTP server to show bundle report. 
       // In `static` mode single HTML file with bundle report will be generated. 
       // In `disabled` mode you can use this plugin to just generate Webpack Stats JSON file by setting `generateStatsFile` to `true`. 
       analyzerMode: 'static', 
       // Host that will be used in `server` mode to start HTTP server. 
       analyzerHost: '127.0.0.1', 
       // Port that will be used in `server` mode to start HTTP server. 
       analyzerPort: 8888, 
       // Path to bundle report file that will be generated in `static` mode. 
       // Relative to bundles output directory. 
       reportFilename: root('./report.html'), 
       // Module sizes to show in report by default. 
       // Should be one of `stat`, `parsed` or `gzip`. 
       // See "Definitions" section for more information. 
       defaultSizes: 'parsed', 
       // Automatically open report in default browser 
       openAnalyzer: false, 
       // If `true`, Webpack Stats JSON file will be generated in bundles output directory 
       generateStatsFile: false, 
       // Name of Webpack Stats JSON file that will be generated if `generateStatsFile` is `true`. 
       // Relative to bundles output directory. 
       statsFilename: 'stats.json', 
       // Options for `stats.toJson()` method. 
       // For example you can exclude sources of your modules from stats file with `source: false` option. 
       // See more options here: https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21 
       statsOptions: null, 
       // Log level. Can be 'info', 'warn', 'error' or 'silent'. 
       logLevel: 'info' 
      }) 
     ); 
    } 

    return config; 
}(); 

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