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


Posted in Javascript onJune 29, 2017

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

查看生成的目录结构

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

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

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

总结:

图片采用了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("style.css")的entry chunks文件中抽离出css到单独的output文件

API

new ExtractTextPlugin([id: string], filename: string, [options])

  1. id Unique ident for this plugin instance. (For advanded usage only, by default automatic generated)
  2. filename the filename of the result file. May contain [name], [id] and [contenthash].
    1. [name] the name of the chunk
    2. [id] the number of the chunk
    3. [contenthash] a hash of the content of the extracted file
  3. options
    1. allChunks extract fromall additional chunks too (by default it extracts only from the initial chunk(s))
    2. disable disables the plugin

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

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

  1. notExtractLoader (可选)当css没有被抽离时,加载器不应该使用(例如:当allChunks:false时,在一个additional 的chunk中)
  2. loader 数组,用来转换css资源的加载器s
  3. options
    1. 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

期望

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

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

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

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

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

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

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

结果:

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

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

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

总结

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

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js屏蔽鼠标键盘(右键/Ctrl+N/Shift+F10/F11/F5刷新/退格键)
Jan 24 Javascript
js Dialog 去掉右上角的X关闭功能
Apr 23 Javascript
用队列模拟jquery的动画算法实例
Jan 20 Javascript
jQuery实现的图文高亮滚动切换特效实例
Aug 10 Javascript
jQuery实现美观的多级动画效果菜单代码
Sep 06 Javascript
JavaScript中数据类型转换总结
Dec 25 Javascript
WebPack基础知识详解
Jan 16 Javascript
vue修改对象的属性值后页面不重新渲染的实例
Aug 09 Javascript
详解解决Vue相同路由参数不同不会刷新的问题
Oct 12 Javascript
详解Vue 全局变量,局部变量
Apr 17 Javascript
微信小程序绑定手机号获取验证码功能
Oct 22 Javascript
Vue 实现html中根据类型显示内容
Oct 28 Javascript
jQuery开源组件BootstrapValidator使用详解
Jun 29 #jQuery
详解webpack 多页面/入口支持&amp;公共组件单独打包
Jun 29 #Javascript
详解webpack 如何集成第三方js库
Jun 29 #Javascript
详解webpack介绍&amp;安装&amp;常用命令
Jun 29 #Javascript
基于node.js制作简单爬虫教程
Jun 29 #Javascript
JavaScript算法教程之sku(库存量单位)详解
Jun 29 #Javascript
详解webpack自动生成html页面
Jun 29 #Javascript
You might like
PHP中数组合并的两种方法及区别介绍
2012/09/14 PHP
ThinkPHP在新浪SAE平台的部署实例
2014/10/31 PHP
thinkphp3.2中Lite文件替换框架入口文件或应用入口文件的方法
2015/05/21 PHP
深入理解PHP内核(二)之SAPI探究
2015/11/10 PHP
jquery获取input表单值的代码
2010/04/19 Javascript
js替换字符串的所有示例代码
2013/07/23 Javascript
js document.write()使用介绍
2014/02/21 Javascript
wap手机图片滑动切换特效无css3元素js脚本编写
2014/07/28 Javascript
实现js保留小数点后N位的代码
2014/11/13 Javascript
使用JavaScript开发IE浏览器本地插件实例
2015/02/18 Javascript
JavaScript中ES6 Babel正确安装过程
2016/07/18 Javascript
jquery 多个radio的click事件实例
2016/12/03 Javascript
H5基于iScroll实现下拉刷新和上拉加载更多
2017/07/18 Javascript
react实现antd线上主题动态切换功能
2019/08/12 Javascript
Jquery如何使用animation动画效果改变背景色的代码
2020/07/20 jQuery
Vue-cli打包后部署到子目录下的路径问题说明
2020/09/02 Javascript
前端vue+elementUI如何实现记住密码功能
2020/09/20 Javascript
[30:51]DOTA2上海特级锦标赛主赛事日 - 3 胜者组第二轮#1Liquid VS MVP.Phx第一局
2016/03/04 DOTA
python开发之字符串string操作方法实例详解
2015/11/12 Python
python字典操作实例详解
2017/11/16 Python
Python(Django)项目与Apache的管理交互的方法
2018/05/16 Python
用pycharm开发django项目示例代码
2018/10/24 Python
Keras - GPU ID 和显存占用设定步骤
2020/06/22 Python
拿来就用!Python批量合并PDF的示例代码
2020/08/10 Python
零基础学python应该从哪里入手
2020/08/11 Python
使用python爬取抖音app视频的实例代码
2020/12/01 Python
Ray-Ban雷朋太阳眼镜英国官网:Ray-Ban UK
2019/11/23 全球购物
幼儿师范毕业生自荐信
2013/11/09 职场文书
质量工程师岗位职责
2013/11/16 职场文书
生物科学专业职业规划书范文
2014/02/11 职场文书
竞选学习委员演讲稿
2014/04/28 职场文书
2015年党员承诺书
2015/01/21 职场文书
工程质量保证书
2015/05/09 职场文书
运动会宣传稿100字
2015/07/23 职场文书
《好妈妈胜过好老师》:每个孩子的优秀都是有源头的
2020/01/03 职场文书
MySQL数据库 安全管理
2022/05/06 MySQL