Skip to content

loader

概念

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。

https://www.webpackjs.com/loaders/

https://www.webpackjs.com/loaders/file-loader/

npm install file-loader -D

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var Header = require('./header.js');
var Sidebar = require('./sidebar.js');
var Content = require('./content.js')
var Content = require('./content.js')
var avatar = require('./avatar.jpg')
console.log(avatar)

new Header();
new Sidebar();
new Content();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.jpg$/,
      use: {
        loader: 'file-loader'
      }
    }]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}

console.log打印出的内容为:30267bc9fc1c4107fffd6d34188a893f.jpg即打包生成的文件名

1
2
3
4
5
6
7
import avatar from './avatar.jpg'

var img = new Image();
img.src = avatar;

var root = document.getElementById('root');
root.append(img);

如果要使用.vue文件,那么就需要相关的loader

https://vue-loader.vuejs.org/zh/

打包静态资源(图片)

打包后指定图片文件名

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.(jpg|pnd|gif)$/,
      // test: /\.jpg$/,
      use: {
        loader: 'file-loader',
        options: {
          // 加中括号的名称为 placeholder 占位符
          name: '[name].[ext]'
          // name: '[name]_[hash].[ext]'
        }
      }
    }]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}

指定outputPath

1
2
3
4
options: {
  name: '[name]_[hash].[ext]',
  outputPath: 'images/'
}

使用url-loader

https://www.webpackjs.com/loaders/url-loader/

直接将file-loader改成url-loader即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.(jpg|pnd|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name]_[hash].[ext]',
          outputPath: 'images/'
        }
      }
    }]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}

如果图片非常小,比较适合将其放到js文件中打包,否则以图片形式打包更好,可以对此进行配置

1
2
3
4
5
6
7
8
use: {
  loader: 'url-loader',
  options: {
    name: '[name]_[hash].[ext]',
    outputPath: 'images/',
    limit: 20480
  }
}

当图片大小小于limit的值,则会打包到js中,否则以图片形式打包

打包静态资源(样式一)

1
npm install style-loader css-loader -D

index.css

1
2
3
4
.avatar {
    width: 150px;
    height: 150px;
}

index.js

1
2
3
4
5
6
7
8
9
import avatar from './avatar.jpg';
import './index.css';

var img = new Image();
img.src = avatar;
img.classList.add('avatar')

var root = document.getElementById('root');
root.append(img);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.(jpg|pnd|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name]_[hash].[ext]',
          outputPath: 'images/',
          limit: 20480
        }
      }
    },{
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    }]
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}

avatar.css

1
2
3
4
.avatar {
    width: 150px;
    height: 150px;
}

index.css

1
@import './avatar.css'

css-loader 解释(interpret) @import 和 url() ,会 import/require() 后再解析(resolve)它们。

sass-loader

https://www.webpackjs.com/loaders/sass-loader/

npm install sass-loader node-sass --save-dev

index.scss

1
2
3
4
5
6
body {
  .avatar {
    width: 150px;
    height: 150px;
  }
}

index.js

1
2
3
4
5
6
7
8
9
import avatar from './avatar.jpg';
import './index.scss';

var img = new Image();
img.src = avatar;
img.classList.add('avatar')

var root = document.getElementById('root');
root.append(img);

loader 的执行顺序为:从下到上,从右到左

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
module: {
  rules: [{
    test: /\.(jpg|pnd|gif)$/,
    use: {
      loader: 'url-loader',
      options: {
        name: '[name]_[hash].[ext]',
        outputPath: 'images/',
        limit: 20480
      }
    }
  },{
    test: /\.scss$/,
    use: ['style-loader', 'css-loader', 'sass-loader']
  }]
},

使用postcss-loader

https://www.webpackjs.com/loaders/postcss-loader/

npm install autoprefixer -D

postcss.config.js

1
2
3
4
5
module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
module: {
  rules: [{
    test: /\.(jpg|pnd|gif)$/,
    use: {
      loader: 'url-loader',
      options: {
        name: '[name]_[hash].[ext]',
        outputPath: 'images/',
        limit: 20480
      }
    }
  },{
    test: /\.scss$/,
    use: [
      'style-loader', 
      'css-loader', 
      'sass-loader',
      'postcss-loader'
    ]
  }]
},

index.scss

1
2
3
4
5
6
7
body {
  .avatar {
    width: 150px;
    height: 150px;
    transform: translate(100px, 100px);
  }
}

打包静态资源(样式二)

avatar.scss

1
2
3
4
5
body {
  .abs {
    background: red;
  }
}

index.scss

1
2
3
4
5
6
7
8
9
@import './avatar.scss';

body {
  .avatar {
    width: 150px;
    height: 150px;
    transform: translate(100px, 100px);
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module: {
  rules: [{
    test: /\.(jpg|pnd|gif)$/,
    use: {
      loader: 'url-loader',
      options: {
        name: '[name]_[hash].[ext]',
        outputPath: 'images/',
        limit: 20480
      }
    }
  },{
    test: /\.scss$/,
    use: [
      'style-loader', 
      {
        loader: 'css-loader',
        options: {
          importLoaders: 2 // 保证依次从下往上调用loader(先执行下面两个loader)
        }
      },
      'sass-loader',
      'postcss-loader'
    ]
  }]
},

样式冲突:

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import avatar from './avatar.jpg';
import './index.scss';
import createAvatar from './createAvatar.js';
createAvatar()
var img = new Image();
img.src = avatar;
img.classList.add('avatar')

var root = document.getElementById('root');
root.append(img);

createAvatar.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import avatar from './avatar.jpg';
function createAvatar() {
  var img = new Image();
  img.src = avatar;
  img.classList.add('avatar')

  var root = document.getElementById('root');
  root.append(img);
}
export default createAvatar;

打包后会出现两张图片,样式都会作用在这两张图片上

为了让css只在某个文件有效,修改webpack.config.js

添加modules: true

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
module: {
  rules: [{
    test: /\.(jpg|pnd|gif)$/,
    use: {
      loader: 'url-loader',
      options: {
        name: '[name]_[hash].[ext]',
        outputPath: 'images/',
        limit: 20480
      }
    }
  },{
    test: /\.scss$/,
    use: [
      'style-loader', 
      {
        loader: 'css-loader',
        options: {
          importLoaders: 2, 
          modules: true
        }
      },
      'sass-loader',
      'postcss-loader'
    ]
  }]
},

就可以写下面的语法import style from './index.scss';

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import avatar from './avatar.jpg';
import style from './index.scss';
import createAvatar from './createAvatar.js';
createAvatar()
var img = new Image();
img.src = avatar;
img.classList.add(style.avatar)

var root = document.getElementById('root');
root.append(img);

createAvatar.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import avatar from './avatar.jpg';
import style from './index.scss';

function createAvatar() {
  var img = new Image();
  img.src = avatar;
  img.classList.add(style.avatar)

  var root = document.getElementById('root');
  root.append(img);
}
export default createAvatar;

字体打包

https://www.iconfont.cn/

1
2
3
4
➜  font pwd
lesson/src/font
➜  font ls
iconfont.eot  iconfont.svg  iconfont.ttf  iconfont.woff

index.scss

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@font-face {font-family: "iconfont";
  src: url('./font/iconfont.eot?t=1570329100796'); /* IE9 */
  src: url('./font/iconfont.eot?t=1570329100796#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOwAAsAAAAAB7wAAANkAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDDAqDDIJiATYCJAMQCwoABCAFhG0HQxu/BlGUDkaP7IckyZkKhRDDsi9AYJkqzQAFCgAsAFCACKL9frN391UgSRKNdLEsWj2RCZ0EoZEiJROKl/Aup/pZg5f+cW9o1LXQRFORX4rieW9lsU5AQ2hpCWgBbAEr7KCcJh2NtAP5Q9QtXLs4nDbPA5tvWS5zjPMxARMMbOwBFmCJZN5jbKDdz3oCbQscjYPD8yvoK4xugXgyWkA/pVRqMkNTqJeMLeINgWZ6SV/Aq//9+BdFn6SWGX2PHw8S2P5S+9LIT1UcFxeBNZ4e3CQyNoFCXJcaT7XC4KaWthJsWwbrahZ8aVQVX2ouc7VNCEkm4K+z0rtgCwX5lFg2heBLXSGdIQuTZEAXTXcSfgbeETt315CkcTze6skNo9rEd2YykF5YmtkeR+/TFLl8zIMpXrGzO7UnhWSQ1LxvURFACjqgDXp90icn+k1j9EfHtpmn9sfHDKDuSJ9y5YSXoPEUOa4e4+aSiScnWq2jwadVD7ElK25ncI1ro6fM6GB1L+1kIiOrOVAc2vvLG0i1sd3iLefdVDLea5M3nXfK1pYLSH9QWiBEUENdY80WISZqzORcrTzHPedmlmcMrRa4FxTruVXY6k1YCtiNf8dnFHHY4hB8lICV17EVOXB8JiBAyIKzs4Az3EO31yeYd2bUX9PCFV+Wrsi3wZWEyM3dEJo090yIPF+tqQRuqZVenWkMgIAblfVr0Q3X7d3dC6jAaIiXjFEH8P+W8/GofNxYtvlFAAACmer61+5U6u7/m6MCPmdrcnBUnwXap2hKcKxfw2pZVlSOoSpF5tpMzVwc9e6a0NZGBYZ17HcM8UzrdELTTAxJwzxkTYvIgt2Emo4tqGvahrYNR5M7JlhLlBbWvQOEoQ9I+j4gG/pGFuwP1Mz6g7phtKDtMiZzdiyHGe4zCUsJTtZoZFkoS2OHQeYF6XkmOMnx8TfEtfFg6AXZyBEVxGMMqBc6slah4jLHQ9iMsqzEissZSetNra1i31dlL/JkmcPQPkYEiyTQxBoypFJBubWtYe7zF4g2lxG4JqtCfYOwmqkfhTxBC+SRsGiVdS2X1Ba0iGUpSGGlHDoEPcnMYAlV5a1miGR5pj38lZhPqqm2Qm9+cf4AGVwexhwlUuQoUdO+YS6XbmIPKbo3manEunUrNAA=') format('woff2'),
  url('./font/iconfont.woff?t=1570329100796') format('woff'),
  url('./font/iconfont.ttf?t=1570329100796') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
  url('./font/iconfont.svg?t=1570329100796#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.iconarrow-down:before {
  content: "\e63b";
}

.iconalipay:before {
  content: "\e63c";
}

.iconbag:before {
  content: "\e63d";
}

index.js

1
2
3
4
var root = document.getElementById('root');
import './index.scss'

root.innerHTML = '<div class="iconfont iconalipay"></div>'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
module: {
  rules: [{
    test: /\.(jpg|pnd|gif)$/,
    use: {
      loader: 'url-loader',
      options: {
        name: '[name]_[hash].[ext]',
        outputPath: 'images/',
        limit: 20480
      }
    }
  },{
    test: /\.(eot|ttf|svg|woff)$/,
    use: {
      loader: 'file-loader'
    }
  },{
    test: /\.scss$/,
    use: [
      'style-loader', 
      {
        loader: 'css-loader',
        options: {
          importLoaders: 2 
        }
      },
      'sass-loader',
      'postcss-loader'
    ]
  }]
},