五、webpack loadles模块加载器
Webpack 常见静态资源处理 - 模块加载器(Loaders)+ExtractTextPlugin插件
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加载器
cnpminstallfile-loader css-loaderstyle-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
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中独立抽离出来
安装
$ npminstallextract-text-webpack-plugin--save-dev
使用(css为例)
varExtractTextPlugin =require("extract-text-webpack-plugin");module.exports = {module: {loaders: [ {test:/\.css$/,loader: ExtractTextPlugin.extract("style-loader","css-loader") } ] },plugins: [newExtractTextPlugin("styles.css") ]}
它将从每一个用到了require("*.css")的entry chunks文件中抽离出css到单独的output文件
API
newExtractTextPlugin([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的使用示例:
letExtractTextPlugin =require('extract-text-webpack-plugin');// multiple extract instancesletextractCSS =newExtractTextPlugin('stylesheets/[name].css');letextractLESS =newExtractTextPlugin('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
安装插件到项目
npminstallextract-text-webpack-plugin--save-dev
配置webpack.config.js,加入ExtractTextPlugin和相关处理:
varwebpack =require("webpack");varpath =require("path");varsrcDir = path.resolve(process.cwd(),'src');varnodeModPath = path.resolve(__dirname,'./node_modules');varpathMap =require('./src/pathmap.json');varglob =require('glob')varCommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;varHtmlWebpackPlugin =require('html-webpack-plugin');varExtractTextPlugin =require('extract-text-webpack-plugin');varentries =function(){varjsDir = path.resolve(srcDir,'js')varentryFiles = glob.sync(jsDir +'/*.{js,jsx}')varmap = {};for(vari =0; i < entryFiles.length; i++) {varfilePath = entryFiles[i];varfilename = filePath.substring(filePath.lastIndexOf('\/') +1, filePath.lastIndexOf('.')); map[filename] = filePath; }returnmap;}varhtml_plugins =function(){varentryHtml = glob.sync(srcDir +'/*.html')varr = []varentriesFiles = entries()for(vari =0; i < entryHtml.length; i++) {varfilePath = entryHtml[i];varfilename = filePath.substring(filePath.lastIndexOf('\/') +1, filePath.lastIndexOf('.'));varconf = {template:'html!'+ filePath,filename: filename +'.html'}//如果和入口js文件同名if(filenameinentriesFiles) { 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(newHtmlWebpackPlugin(conf)) }returnr}varplugins = [];varextractCSS =newExtractTextPlugin('css/[name].css?[contenthash]')varcssLoader = extractCSS.extract(['css'])varsassLoader = extractCSS.extract(['css','sass'])plugins.push(extractCSS);plugins.push(newCommonsChunkPlugin({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
varExtractTextPlugin =require('extract-text-webpack-plugin');varextractCSS =newExtractTextPlugin('css/[name].css?[contenthash]')varcssLoader = extractCSS.extract(['css'])varsassLoader = 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 发布 前端自动化构建的项目模板

浙公网安备 33010602011771号