【问题标题】:angular2 webpack large bundle size with sass带有sass的angular2 webpack大包大小
【发布时间】:2016-12-22 04:04:27
【问题描述】:

我遇到了由 sass 样式引起的 webpack 包大小问题...

我有许多使用 materialize-css 库设计的 angular2 组件。我使用 @extend 而不是将 materialize-css 类放在我的 html 中来封装 html 本身的库。

我遇到的问题是 webpack 的包大小非常大,因为每个组件的 sass 都会导入 materialize-css 包,并且因为组件的样式是使用 raw 加载器加载的,所以它会嵌入到包 js 文件中。所以我得到的是每个组件都具有相同 materialize-css 样式的巨大捆绑包。

只是为了比较我编译的应用程序中所有样式都被注释掉了,捆绑包大小为 1.08MB,包含样式时为 5.26MB

谁能指出正确的解决方案?

谢谢!

编辑: 我的 webpack 定义:

Webpack.common:

import * as webpack from 'webpack';
import {Configuration} from 'webpack';
import * as path from 'path';
import {PathHelper} from '../../common/pathHelper';
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');

process.env.ENV = process.env.NODE_ENV;

export var webpackCommonConfiguration: Configuration = {
  entry: {
    'polyfills': './src/app/polyfills.ts',
    'app': './src/app/app.ts',
    'signin': './src/app/signinApp.ts',
    'vendor': './src/app/vendor.ts',
    'design': './src/app/design.scss'
  },
  resolve: {
    extensions: ['', '.ts', '.js', 'scss']
  },
  module: {
    loaders: [
      {
        test: /\.ts$/,
        loader: 'ts'
      },
      {
        test: /\.html$/,
        loader: 'html'
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'file?name=assets/[name].[hash].[ext]'
      },
      {
        test: /\.scss$/,
        exclude: PathHelper.getPathFromRoot('src', 'app', 'modules'),
        loader: ExtractTextPlugin.extract('style', 'css!resolve-url!sass?sourceMap')
      },
      {
        test: /\.scss$/,
        include: PathHelper.getPathFromRoot('src', 'app', 'modules'),
        loader: 'raw!sass'
      },
      {
        test: /\.css$/,
        exclude: PathHelper.getPathFromRoot('src', 'app', 'modules'),
        loader: ExtractTextPlugin.extract('style', 'css!resolve-url!css?sourceMap')
      },
      {
        test: /\.css$/,
        include: PathHelper.getPathFromRoot('src', 'app', 'modules'),
        loader: 'raw!resolve-url'
      }
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'signinCommon',
      chunks: ['signin', 'vendor'],
      minChunks: Infinity
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'homeCommon',
      chunks: ['app', 'vendor'],
      minChunks: Infinity
    }),
    new webpack.DefinePlugin({
      'process.env': {
        'ENV': JSON.stringify(process.env.NODE_ENV)
      }
    }),
    new webpack.ProvidePlugin({
      // Required for the velocity plugin to be loaded correctly (used in materialize css)
      "window.$": "jquery",
      "window.jQuery": "jquery",
      "root.jQuery": "jquery"
    }),
    new HtmlWebpackPlugin({
      template: PathHelper.getPathFromRoot('src', 'app', 'views', 'signin.html'),
      filename: 'signin.html',
      chunks: ['polyfills', 'signinCommon', 'design', 'vendor', 'signin']
    }),
    new HtmlWebpackPlugin({
      template: PathHelper.getPathFromRoot('src', 'app', 'views', 'home.html'),
      filename: 'home.html',
      chunks: ['polyfills', 'homeCommon', 'design', 'vendor', 'app']
    })
  ]
}

Webpack.prod:

var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
import * as webpack from 'webpack';
import {Configuration} from 'webpack';
import {webpackCommonConfiguration} from './webpack.common.config'
import {PathHelper} from '../../common/pathHelper';

interface IProductionConfiguration extends Configuration {
  htmlLoader: any;
}

var config: IProductionConfiguration = {

  devtool: 'source-map',

  output: {
    path: PathHelper.getPathFromRoot('dist'),
    publicPath: '/dist/',
    filename: '[name].[hash].js',
    chunkFilename: '[id].[hash].chunk.js'
  },

  htmlLoader: {
    minimize: false // workaround for ng2
  },

  plugins: [
    new webpack.NoErrorsPlugin(),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin(),
    new ExtractTextPlugin('[name].[hash].css')
  ]
}

export var webpackProductionConfig: Configuration =
  webpackMerge(webpackCommonConfiguration, config);

编辑2: 组件示例:

credits.component.ts:

import {Component} from '@angular/core';

@Component({
  selector: 'credits',
  template: require('./credits.component.html'),
  styles: [require('./credits.component.scss')]
})
export class CreditsComponent {
}

credits.component.html:

<footer class="page-footer credits-footer">
  <div class="footer-copyright">
    <div class="container">
    © 2016 Created by Slava Shpitalny
    </div>
  </div>
</footer>

credits.component.scss:

@import '~materialize-css/sass/materialize.scss';

:host{

  .page-footer.credits-footer{
    @extend .blue;
    margin: 0;
    padding: 0;

  }
}

【问题讨论】:

  • 更新了我的答案,希望对您有所帮助:)

标签: angular typescript sass webpack


【解决方案1】:

您可以在您的主应用组件上使用ViewEncapsulation.None,并将 Materialize.scss 导入您应用的 SCSS 文件。然后它将在全球范围内可用,您无需将其导入其他组件。

例如,您的应用组件可能如下所示:

import { ViewEncapsulation } from '@angular/core';
@Component({
    selector: 'app',
    encapsulation: ViewEncapsulation.None,
    styles: [require('./app.scss')],
    template: require('./app.html')
})

...只有您的主应用程序的 SCSS 文件将包含导入:

@import '~materialize-css/sass/materialize.scss';

注意:您可以只导入您使用的 Materialize 组件,而不是导入 materialize.css。这样会更有效率。

如果您想在子组件中使用变量/mixin,您可以单独导入它们(但不要导入整个 Materialize scss!)。

例如,子组件可能会导入_variables.scss 和_mixins.scss,而不仅仅是materialize.scss。

例如:

@import '~materialize-css/sass/components/_mixins.scss';
@import '~materialize-css/sass/components/_variables.scss';

别忘了,vars/mixins 不会被导出,只会导出 SCSS 转译的 CSS 结果,所以如果不使用它们不会增加文件大小(不像主 Materialize.scss 文件包含很多CSS 类)

【讨论】:

  • 为了使@extend 行工作,我需要将materialize 导入到组件sass 文件中,我将研究我需要导入的最小部分以使其工作......
  • 是的,你不能为此只导入 _color.scss 吗?
  • 好的,我检查了所有组件,只导入了需要的文件。仍然有多次复制的样式,例如:_color、_variables、_typography、_global、_buttons、_grid,我将它们添加到我常用的_forms 样式和其他组件中。现在的包大小是 2.27MB,这是很大的改进,但我的应用程序会随着时间的推移变得更大,至少是组件数量的两倍。所以现有组件的最小样式增加了大约 1.2MB,还有其他建议吗?
  • 当您说 2.27mb 时,是在最小化和捆绑之前吗?在浏览器中使用 gzip 之前?
  • 在最小化之后..在其 10 MB 之前...gzip?
【解决方案2】:

不要仅捆绑到单个文件。单独捆绑,例如一个用于供应商,一个用于 pollyfills,一个用于应用程序,一个用于 css。使用ExtractTextPlugin插件创建自己的css文件。使用 webpack 块让生活更轻松。对大型应用程序使用代码拆分。

Read more about it

在生产模式下,您可以使用一些插件来缩小捆绑包、删除 cmets、删除未使用的代码。

【讨论】:

  • 我添加了我的 webpack 配置。你能举例说明你的意思吗?
  • 看起来不错。您正在使用代码拆分和 ExtractTextPlugin。你要单独获得 design.css 吗? here is a seed i been working on, bit different
  • 是的,问题是因为组件是使用 raw 加载器编译的,样式最终在组件 javascript 文件中......这与在 sass 中的 import 的实现创建问题。每次我导入 materialize-css 库时,它都会被复制。原始加载器运行后,样式作为字符串注入到组件内部,因此它没有得到任何处理...
  • 我添加了简单的组件示例
  • 我从未使用过 sass,但我想这样做。据我所知,webpack 应该将 sass 编译为 css,然后将其打包。
猜你喜欢
  • 2021-07-12
  • 1970-01-01
  • 2016-12-15
  • 2017-05-14
  • 2018-04-22
  • 2016-03-18
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
相关资源
最近更新 更多