webpack scss打包

2,967 阅读2分钟

webpack scss打包

webpack将css打包成一个bundle文件,对于打包遇到的一些问题做一些总结。

前言

因为基于sass打包,所以先讲解一下sass基础知识。

!default 默认值

Notes: 变量可以覆盖,但是无法变量提升

$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;

#main {
  content: $content;
  new-content: $new_content;
}

$content: "Hoisting content";

#submain {
  content: $content;
  new-content: $new_content;
}

this Compiled Result:

#main {
  content: "First content";
  new-content: "First time reference";
}

#submain {
  content: "Hoisting content";
  new-content: "First time reference";
}

@import 导入

Sass 拓展了 @import 的功能,允许其导入 SCSS 或 Sass 文件。被导入的文件将合并编译( 先合并再编译)到同一个 CSS 文件中,另外,被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用。

片段(Partials)需要导入 SCSS 或者 Sass 文件,但又不希望将其编译为 CSS,只需要在文件名前添加下划线,将文件命名为 _colors.scss,便不会编译 _colors.css 文件。

@import "colors";

Notes:webpack打包js文件可以extensions补全后缀.js,但是因为scss的Partials所以无法使用补全。

require/import

webpack在ES6模块加载打包时是先编译再合并

webpack配置

const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// bundle
const extractSass = new ExtractTextPlugin({
  filename: '[name].css',
  allChunks: false
})

const config = {
  entry: {
    index: ['babel-polyfill', './screen/demo/index.jsx']
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
    libraryTarget: 'umd',
  },
  module: {
    {
      test: /\.(scss|sass)$/,
      use: extractSass.extract({
        use: [{
          loader: "css-loader"
        }, {
          loader: "sass-loader"
        }],
        // use style-loader in development
        fallback: "style-loader"
      })
    }],
  },
  resolve: {
    extensions: ['*', '.js', '.jsx'], // 后缀名自动补全
    mainFiles: ['index'], // 默认js文件名
  },
  plugins: [
    extractSass
  ]
};

module.exports = [config];

使用

一、@import

1、简单

variable.scss

$white: #fff;

a.scss

@import 'variable.scss';
html{
	background-color: $white;
}

b.scss

@import 'variable.scss';
body{
	background-color: $white;
}

this Compiled Result:

/*a.scss*/
html{
	background-color: #fff;
}

/*b.scss*/
body{
	background-color: #fff;
}

2、嵌套

variable.scss

$white: #fff;

a.scss

/*@import 'variable.scss';*/
html{
	background-color: $white;
}

b.scss

@import 'variable.scss';
@import 'b.scss';
body{
	background-color: $white;
}

this Compiled Result:

/*b.scss*/
html{
	background-color: #fff;
}
body{
	background-color: #fff;
}

3、复杂嵌套

variable.scss

$white: #fff;

component.scss

@import 'variable.scss';
.component{
	background-color: $white;
}

a.scss

/*@import 'variable.scss';*/
@import 'component.scss';
html{
	background-color: $white;
}

b.scss

@import 'variable.scss';
@import 'a.scss';
@import 'component.scss';
body{
	background-color: $white;
}

this Compiled Result:

/*b.scss*/
.component{
	background-color: #fff;
}
html{
	background-color: #fff;
}
/* this is duplicated */
.component{
	background-color: #fff;
}
body{
	background-color: #fff;
}

仔细看发现编译后的结果component.scss被重复编译,因为@import是合并文件,但是variable和mixin是不会被编译输出的,嵌套使用@import注意不要重复class,推荐写法:

新增index.scss

@import 'variable.scss';
@import 'a.scss';
@import 'b.scss';
@import 'component.scss';

a.scss

@import 'variable.scss';
/*@import 'component.scss';*/
html{
	background-color: $white;
}

b.scss

@import 'variable.scss';
/*@import 'a.scss';
@import 'component.scss';*/
body{
	background-color: $white;
}

最好就是统一入口引用,按需求嵌套,防止重复。但是顶层scss文件引入变量文件就可以使用的,为什么要每个文件都引用@import 'variable.scss';?后面会讲解。

4、node_modules模块

@import "~bootstrap/dist/css/bootstrap";

使用~声明不是相对地址,而是来自node_modules下的模块

二、require/import

variable.scss

$white: #fff;

a.scss

@import 'variable.scss';
html{
	background-color: $white;
}

b.scss

/*@import 'variable.scss';*/
body{
	background-color: $white;
}

a.jsx

import React, { Component } from 'react';
import './a.scss';

const TestA = (props, context)=>{
  return (
    <div className="test-child-background">test123456</div>
  );
}

export default TestA;

b.jsx

import React, { Component } from 'react';
// quote variable.scss
import TestA from './a.jsx';
// not quote variable.scss
import './b.scss';

const TestB = (props)=>{
  return (
    <div className="test-background">
      <TestA />
    </div>
  );
}

export default TestB;
//b.scss error
Undefined variable: "$white"

@import**是全局变量通用,先合并在编译,**而es6 Module语法import是按照单个文件加载的,webpack会先编译在合并,但是不会影响单个import的scss文件中的@import语法。a.scssb.scss是分开编译在合并成一个文件,所以每个_单独的scss_文件最好引用全局变量文件。

优点:

  • 引用全局变量文件,利于组件重用,不受引用文件作用域影响;

缺点:

  • 如果是纯样式scss文件,@import将会重复引用class,需要自己注意,issues有讨论,但是没有优美的解决方案。(less有@import (reference) 'base.less';语法来支持重复引用)