介绍
webpack将所有静态资源都认为是模块,比如javascript,css,less,typescript,jsx,图片等等。webpack引入了加载器的loader,对除javascript之外的资源处理成模块。
webpack的加载器之间可以进行串联,一个加载器的输出可以成为另一个加载器的输入。
Webpack将所有静态资源都认为是模块,而通过loader,几乎可以处理所有的静态资源,图片、css、sass之类的。并且通过一些插件如extract-text-webpack-plugin,可以将共用的css抽离出来
常用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 {
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
生产的目录结构
其中没有css文件,css被写入index.js中,index.js部分截图
- 图片用url-loader加载器处理,如果小于10kb,图片则被转化成base64格式的dataUrl
- css文件打包进入了js文件,如果不想css打包进js文件,可以强制吧css从js文件中国独立出来。webpack.js.org
extract-text-webpack-plugin
此类插件可以将公用的css抽离出来,从bundle中提取出特定的text到一个文件中。这样就可以把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文件。
多入口文件的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
]
};
extractTextPlugin的api
new ExtractTextPlugin([id:string], filename: string, [options] )
- id:此插件实列唯一的标识。(仅用于高级用途,默认情况下自动生成)
- filename:结果文件的文件名。可以包含【name】、【id】和【contenthash】
- options:allchunks | disable。allchunks也从所有其他块中提取(默认情况下,它只从初始块中提取),disable禁用插件
ExtractTextPlugin.extract([notExtractLoader], loader , [options])
根据已有的loader,创建一个提取器,loader的再封装
4. notExtractLoader:(可选)当css没有被抽离时,加载器不应该使用(例如:当allChunks:false时,在一个additional 的chunk中)
5. loader:数组,用来转换css资源的加载器
6. options:publicPath,重写该加载器的设置
改造项目
cnpm install extract-text-webpack-plugin --save-dev
安装插件到项目
修改webpack.config.js
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 会被压缩,减少文件大小
- 生成的 dist/index.html 自动引用了 index.css 和相关的js,由于设置了publicPath 所以相应的链接都采用了绝对路径
- 生成的 dist/index.css 小图片被转成了data:image形式:
1、css单独打包到css目录
2、html自动注入了link 标签
3、small-webpack.png 小于10k,被打包进了index.css
4、webpack.png 由原来的50+k 被压缩成 10- k
webpack-dev-server
看一下结果