Webpack 常见静态资源处理 - 模块加载器(Loaders)+ExtractTextPlugin插件

webpack系列目录

基于webpack搭建纯静态页面型前端工程解决方案模板, 最终形态源码见github: https://github.com/ifengkou/webpack-template

正文

Webpack将所有静态资源都认为是模块,比如JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,图片等等,从而可以对其进行统一管理。为此Webpack引入了加载器的概念,除了纯JavaScript之外,每一种资源都可以通过对应的加载器处理成模块。和大多数包管理器不一样的是,Webpack的加载器之间可以进行串联,一个加载器的输出可以成为另一个加载器的输入。比如LESS文件先通过less-load处理成css,然后再通过css-loader加载成css模块,最后由style-loader加载器对其做最后的处理,从而运行时可以通过style标签将其应用到最终的浏览器环境。

一 常用loader

安装css/sass/less loader加载器

cnpm install file-loader css-loader style-loader sass-loader ejs-loader html-loader jsx-loader image-webpack-loader --save-dev

webpack.config.js配置:

module: {
loaders: [
{
test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
loaders: [
// 小于10KB的图片会自动转成dataUrl
'url?limit=10240&name=img/[hash:8].[name].[ext]',
'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
]
},
{
test: /\.((ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9]))|(ttf|eot)$/,
loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
},
{test: /\.(tpl|ejs)$/, loader: 'ejs'},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{ test: /\.scss$/, loader: 'style!css!sass'}
]
},

index.html 新增两个div

<div class="small-webpack"></div>
<div class="webpack"></div>

index.css 增加两个图片,同时将webpack.png(53kb) 和 small-webpack.png(9.8k)

.webpack {
background: url(../img/webpack.png) no-repeat center;
height:500px;
}
.small-webpack {
background: url(../img/small-webpack.png) no-repeat center;
height:250px;
}

index.js 引入css

require('../css/index.css');

执行webpack指令

$ webpack

查看生成的目录结构

其中并没有css文件,css被写入到了index.js中,index.js 部分截图

总结:

  • 图片采用了url-loader加载,如果小于10kb,图片则被转化成 base64 格式的 dataUrl
  • css文件被打包进了js文件中

css被打包进了js文件,如果接受不了,可以强制把css从js文件中独立出来。官方文档是以插件形式实现:文档docs点这插件的github点这

二:extract-text-webpack-plugin 插件介绍

Extract text from bundle into a file.从bundle中提取出特定的text到一个文件中。使用 extract-text-webpack-plugin就可以把css从js中独立抽离出来

安装

$ npm install extract-text-webpack-plugin --save-dev

使用(css为例)

var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
module: {
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
]
},
plugins: [
new ExtractTextPlugin("styles.css")
]
}

它将从每一个用到了require("*.css")的entry chunks文件中抽离出css到单独的output文件

API

new ExtractTextPlugin([id: string], filename: string, [options])
  • id Unique ident for this plugin instance. (For advanded usage only, by default automatic generated)

  • filename the filename of the result file. May contain [name], [id] and [contenthash].

    • [name] the name of the chunk
    • [id] the number of the chunk
    • [contenthash] a hash of the content of the extracted file
  • options

    • allChunks extract from all additional chunks too (by default it extracts only from the initial chunk(s))
    • disable disables the plugin

    ExtractTextPlugin.extract([notExtractLoader], loader, [options])

根据已有的loader,创建一个提取器(loader的再封装)

  • notExtractLoader (可选)当css没有被抽离时,加载器不应该使用(例如:当allChunks:false时,在一个additional 的chunk中)
  • loader 数组,用来转换css资源的加载器s
  • options
    • publicPath 重写该加载器(loader)的 publicPath 的设置

多入口文件的extract的使用示例:

let ExtractTextPlugin = require('extract-text-webpack-plugin');

// multiple extract instances
let extractCSS = new ExtractTextPlugin('stylesheets/[name].css');
let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); module.exports = {
...
module: {
loaders: [
{test: /\.scss$/i, loader: extractCSS.extract(['css','sass'])},
{test: /\.less$/i, loader: extractLESS.extract(['css','less'])},
...
]
},
plugins: [
extractCSS,
extractLESS
]
};

三:改造项目-抽离css

安装插件到项目

npm install extract-text-webpack-plugin --save-dev

配置webpack.config.js,加入ExtractTextPlugin和相关处理:

var webpack = require("webpack");
var path = require("path");
var srcDir = path.resolve(process.cwd(), 'src');
var nodeModPath = path.resolve(__dirname, './node_modules');
var pathMap = require('./src/pathmap.json');
var glob = require('glob')
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var entries = function () {
var jsDir = path.resolve(srcDir, 'js')
var entryFiles = glob.sync(jsDir + '/*.{js,jsx}')
var map = {}; for (var i = 0; i < entryFiles.length; i++) {
var filePath = entryFiles[i];
var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
map[filename] = filePath;
}
return map;
} var html_plugins = function () {
var entryHtml = glob.sync(srcDir + '/*.html')
var r = []
var entriesFiles = entries()
for (var i = 0; i < entryHtml.length; i++) {
var filePath = entryHtml[i];
var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
var conf = {
template: 'html!' + filePath,
filename: filename + '.html'
}
//如果和入口js文件同名
if (filename in entriesFiles) {
conf.inject = 'body'
conf.chunks = ['vendor', filename]
}
//跨页面引用,如pageA,pageB 共同引用了common-a-b.js,那么可以在这单独处理
//if(pageA|pageB.test(filename)) conf.chunks.splice(1,0,'common-a-b')
r.push(new HtmlWebpackPlugin(conf))
}
return r
}
var plugins = [];
var extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
var cssLoader = extractCSS.extract(['css'])
var sassLoader = extractCSS.extract(['css', 'sass']) plugins.push(extractCSS); plugins.push(new CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity
})); module.exports = {
entry: Object.assign(entries(), {
// 用到什么公共lib(例如jquery.js),就把它加进vendor去,目的是将公用库单独提取打包
'vendor': ['jquery', 'avalon']
}),
output: {
path: path.join(__dirname, "dist"),
filename: "[name].js",
chunkFilename: '[chunkhash:8].chunk.js',
publicPath: "/"
},
module: {
loaders: [
{
test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
loaders: [
//小于10KB的图片会自动转成dataUrl,
'url?limit=10000&name=img/[hash:8].[name].[ext]',
'image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:"65-80",speed:4}}'
]
},
{
test: /\.((ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9]))|(ttf|eot)$/,
loader: 'url?limit=10000&name=fonts/[hash:8].[name].[ext]'
},
{test: /\.(tpl|ejs)$/, loader: 'ejs'},
{test: /\.css$/, loader: cssLoader},
{test: /\.scss$/, loader: sassLoader}
]
},
resolve: {
extensions: ['', '.js', '.css', '.scss', '.tpl', '.png', '.jpg'],
root: [srcDir, nodeModPath],
alias: pathMap,
publicPath: '/'
},
plugins: plugins.concat(html_plugins())
}

其中,用ExtractTextPlugin 来抽离css

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractCSS = new ExtractTextPlugin('css/[name].css?[contenthash]')
var cssLoader = extractCSS.extract(['css'])
var sassLoader = extractCSS.extract(['css', 'sass']) plugins.push(extractCSS);
......
//conf - module - loaders
{test: /\.css$/, loader: cssLoader},
{test: /\.scss$/, loader: sassLoader}

注意事项:

  • css中img的路径会出现问题,通过设置publicPath 解决,采用绝对路径

      output: {
    ......
    publicPath: "/"
    },

运行:

$ webpack

期望

  • css单独抽离,打包成单独的css文件
  • html自动引用css文件
  • 小于10k的图片,转成base64 格式的 dataUrl
  • webpack.png 会被压缩,减少文件大小

运行webpack后的项目的目录结构:

生成的 dist/index.html 自动引用了 index.css 和相关的js,由于设置了publicPath 所以相应的链接都采用了绝对路径

生成的 dist/index.css 小图片被转成了data:image形式:

结果:

  • css单独打包到css目录
  • html自动注入了link 标签
  • small-webpack.png 小于10k,被打包进了index.css
  • webpack.png 由原来的50+k 被压缩成 10- k

最后,运行 webpack-dev-server 看一下运行结果:

总结

Webpack将所有静态资源都认为是模块,而通过loader,几乎可以处理所有的静态资源,图片、css、sass之类的。并且通过一些插件如extract-text-webpack-plugin,可以将共用的css抽离出来

下篇介绍改进webpack.config.js:

  • 区分开发环境和生产环境
  • 集成 gulp 实现自动构建打包部署
  • github 发布 前端自动化构建的项目模板

Webpack 常见静态资源处理 - 模块加载器(Loaders)+ExtractTextPlugin插件的更多相关文章

  1. Webpack模块加载器

    一.介绍 Webpack是德国开发者 Tobias Koppers 开发的模块加载器,它能把所有的资源文件(JS.JSX.CSS.CoffeeScript.Less.Sass.Image等)都作为模块 ...

  2. 实现简单的 JS 模块加载器

    实现简单的 JS 模块加载器 1. 背景介绍 按需加载是前端性能优化的一个重要手段,按需加载的本质是从远程服务器加载一段JS代码(这里主要讨论JS,CSS或者其他资源大同小异),该JS代码就是一个模块 ...

  3. 构建服务端的AMD/CMD模块加载器

    本文原文地址:http://trock.lofter.com/post/117023_1208040 . 引言:  在前端开发领域,相信大家对AMD/CMD规范一定不会陌生,尤其对requireJS. ...

  4. 【模块化编程】理解requireJS-实现一个简单的模块加载器

    在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题: ① 解决单文件变量命名冲突问题 ② 解决前端多人协作问题 ③ 解决文件依赖问题 ④ 按需加载(这个说法其实很假了) ⑤ ..... ...

  5. JavaScript AMD 模块加载器原理与实现

    关于前端模块化,玉伯在其博文 前端模块化开发的价值 中有论述,有兴趣的同学可以去阅读一下. 1. 模块加载器 模块加载器目前比较流行的有 Requirejs 和 Seajs.前者遵循 AMD规范,后者 ...

  6. js模块化/js模块加载器/js模块打包器

    之前对这几个概念一直记得很模糊,也无法用自己的语言表达出来,今天看了大神的文章,尝试根据自己的理解总结一下,算是一篇读后感. 大神的文章:http://www.css88.com/archives/7 ...

  7. 实现一个类 RequireJS 的模块加载器 (二)

    2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...

  8. 使用RequireJS并实现一个自己的模块加载器 (一)

    RequireJS & SeaJS 在 模块化开发 开发以前,都是直接在页面上引入 script 标签来引用脚本的,当项目变得比较复杂,就会带来很多问题. JS项目中的依赖只有通过引入JS的顺 ...

  9. JS模块加载器加载原理是怎么样的?

    路人一: 原理一:id即路径 原则.通常我们的入口是这样的: require( [ 'a', 'b' ], callback ) .这里的 'a'.'b' 都是 ModuleId.通过 id 和路径的 ...

随机推荐

  1. mycat->oracle报java.sql.SQLException: 无法从套接字读取更多的数据

    今天下午,测试环境清算的时候又出现了之前的一个异常,这次把错误信息全部打出来了,java.sql.SQLException: 无法从套接字读取更多的数据,是使用mycat连接oracle的,如下所示: ...

  2. j2ee分布式缓存同步实现方案dlcache

    现成的分布式K/V缓存已经有很多的实现,最主要的比如redis,memcached,couchbase.那为什么我们还要自己去实现呢,在我们解决了分布式系统下大量rpc调用导致的高延时后,我们发现很多 ...

  3. 02: djangorestframework使用

    1.1 djangorestframework登录.认证和权限 1.认证与权限相关模块 # -*- coding: utf-8 -*- from django.utils import six fro ...

  4. ldap集成zabbix

    zabbix版本:3.0.7 ldap认证配置: zabbix管理员登录-->管理-->认证,选择ldap方式 参照以上格式填写,需注意配置完成后需在zabbix上创建与ldap同名账户才 ...

  5. linux下 GCC编译链接静态库&动态库

    静态库 有时候需要把一组代码编译成一个库,这个库在很多项目中都要用到,例如libc就是这样一个库, 我们在不同的程序中都会用到libc中的库函数(例如printf),也会用到libc中的变量(例如以后 ...

  6. Window 对象 HTML框架标签(Frame)

    Window 对象 Window 对象表示浏览器中打开的窗口. 如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外 ...

  7. Bootstrap3基础 input-group-btn 按钮与输入框 横向组合

      内容 参数   OS   Windows 10 x64   browser   Firefox 65.0.2   framework     Bootstrap 3.3.7   editor    ...

  8. Vim 学习

    主要分为三种模式: 一般模式 编辑模式 命令行模式 光标的移动 单词级 比单纯的逐个字符的移动,效率要高 w or W 向移动到下一单词开头 ★★ b or B 向左移动到单词开头 ★★ 块级 gg文 ...

  9. linux内核中的最简单的输入输出调度算法noop

    1. noop是什么? noop是一种输入输出调度算法 2. noop的别称 又称为电梯调度算法 3. noop原理是怎样的? 将输入输出请求放到一个FIFO队列中,然后按次序执行队列中的输入输出请求 ...

  10. grub基本应用

    一.基本概念 GRUB(boot  loader):  GRand Unified Bootloader 两个版本: grub .x: grup legacy grub .x: grub2 grub ...