Webpack常见静态资源处理-模块加载器(Loaders)+ExtractTextPlugin插件
webpack系列目录
webpack 系列 五:webpack loaders 模块加载器
基于webpack搭建纯静态页面型前端工程解决方案模板, 最终形态源码见github:
正文
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文件中独立出来。官方文档是以插件形式实现:,
二: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])
- 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 fromall 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 发布 前端自动化构建的项目模板
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。