自从出现模块化之后,你们能够将本来一坨代码分离到个个模块中,可是由此引起了一个问题。每一个 JS 文件都须要从服务器去拿,由此会致使加载速度变慢。Webpack 最主要的目的就是为了解决这个问题,将全部小文件打包成一个或多个大文件,官网的图片很好的诠释了这个事情,除此以外,Webpack 也是一个能让你使用各类前端新技术的工具。css
webpack一共经历了4个版本,分别是一、二、三、4,最新版本是4,如下案例是基于4实践的html
——自来《深刻浅出webpack》前端
全局安装webpackvue
npm install -g webpack
复制代码
局部安装webpacknode
npm install --save-dev webpack
复制代码
webpack -p 执行一次生成环境的编译(压缩)
webpack --watch 在开发时持续监控增量编译(很快)
webpack -d 让他生成SourceMaps
webpack --progress 显示编译进度
webpack --colors 显示静态资源的颜色
webpack --sort-modules-by, --sort-chunks-by, --sort-assets-by 将modules/chunks/assets进行列表排序
webpack --display-chunks 展现编译后的分块
webpack --display-reasons 显示更多引用模块缘由
webapck --display-error-details 显示更多报错信息
复制代码
配置模块的入口jquery
Entry参数说明,类型能够是如下三种中的一种或者相互组合webpack
类型 | 例子 | 含义 |
---|---|---|
string | './app/entry' | 入口模块的文件路径,能够相对路径 |
array | ['./app/entry1','./app/entry2'] | 入口模块的文件路径,能够是相对路径 |
object | {a:['./app/entry-a'],b:['./app/entry-b1','./app/entry-b2']} | 配置多个入口,每一个入口生成一个chunk |
配置如何输出最终想要的代码git
output是一个object,里面包含一系列配置项
output.filename:'[name].js' //输出文件的名称
也可使用hash、chunkhash、contenthash来命名,关于hash、chunkhash、contenthash区别能够参考https://www.cnblogs.com/tugenhua0707/p/9615822.html#_labe1_2
output.chunkFilename://chunkFilename 和上面的 filename 很是相似,但 chunkFilename 只用于指定在运行过程当中生成的 Chunk 在输出时的文件名称,vue按需加载就可使用这个参数
output.path:path .resolve( dirname, ’ dist [hash]’) //path 配置输出文件存放在本地的目录
output.publicPath:'https://cdn.example.com/assets/' //配置发布到线上资源的 URL 前缀
output.libraryTarget://配置以何种方式导出库,可选值var、commonjs、commonjs二、this、window、global
output.library://配置导出库的名称。
output.libraryExport: 配置要导出的模块中哪些子模块须要被导出
复制代码
3.1 rulesgithub
rules 配置模块的读取和解析规则,一般用来配置 Loader。大体能够经过如下方式来完成web
条件匹配:经过 test、 include、 exclude 三个配置项来选中 Loader 要应用 规则的文件。
应用规则:对选中的文件经过 use 配置项来应用 Loader,能够只应用一个 Loader或者按照从后往前的顺序应用一组 Loader,同时能够分别向 Loader传入参数。
重置顺序:一组 Loader 的执行顺序默认是从右到左执行的,经过 enforce 选项能够将其中 一个 Loader 的执行顺序放到最前或者最后 。
具体方法:
module:{
rules:[
{
//命中 JavaScript 文件
test: /\.js$/,
//用 babel-loader 转换 JavaScript 文件
//?cacheDirectory 表示传给 babel-loader 的参数,用于缓存 babel 的编译结果,
use : [’ babel-loader?cacheDirectory ’],
//只命中 src 目录里的 JavaScript 文件,加快 Webpack 的搜索速度
include: path.resolve( dirname, ’ src ’)
},
{
//命中scss文件
test:/\.scss$/,
//使用一组loader去处理scss文件
//处理顺序为从后到前,即先交给 sass-loader处理,再将结果交给 css-loader,最后交给 style-loader
use:['style-loader','css-loader','sass-loader'],
//排除node_modules目录下的文件
exclude: path.resolve( dirname, ’ node modules ’)
},
{
//对非文件采用file-loader加载
test:/\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
use:['file-loader']
}
]
}
复制代码
3.2 noParse
配置项可让Webpack忽略对部分没采用模块化的文件的递归解析和处理,这样作的好处能提升构建性能。
//使用正则表达式
noParse: /jquerylchartjs/
复制代码
注意,被忽略的文件里不该该包含 import、 require、 define 等模块化 语句,不 然会致使在构建出的代码中包含没法在浏览器环境下执行的模块化语句 。
3.3. parse
parser 属性能够更细粒度地配置 哪些模块语法被解析、哪些不被解析。同 noParse 配置项的区别在于, parser 能够精确到 语法层 面,而 noParse 只能控制哪些文件不被解析。
parser 的使用方法以下:
module: {
rules : [
{
test: /\.js♀/,
use: [ ’ babel-loader ’],
parser: {
amd: false, //禁用AMD
commonjs : false , //禁用 CommonJS
system : false, //禁用 SystemJS
harmony: false, //禁用 ES6 import/export
requireinclude:false, //禁用require.include
requireEnsure: false, //禁用require.ensure
requireContext:false, //禁用require.context
browserify: false, //禁用 browserify requireJs : false, //禁用 requirejs:false
requireJs : false, //禁用 requirejs
}
}
]
}
复制代码
配置寻找模块的规则
4.1. alias
配置项经过别名来将原导入路径映射成一个新的导入路径
resolve:{
alias:{
components:'./src/components/'
}
}
复制代码
4.2. mainFields
会根据 mainFields 的配 置去决定 优先采用哪份代码,
mainFields : [’jsnext:main’,’browser’,’main’]
复制代码
4.3. extensions
Webpack 会自动带上后缀后去尝试访问文件是否存在。 resolve.extensions 用于配置在尝试过程当中用到的后缀列表
extensions:[’.ts’,’.j5 ’,’.json’]
复制代码
配置扩展插件
plugins配置项接收一个数组,数组里的每一项都是一个要使用 的 Plugin 的实例, Plugin 须要的参数经过构造函数传入,mini-css-extract-plugin、clean-webpack-plugin、DllReferencePlugin、html-webpack-plugin、happyPack、webpack-parallel-uglify-plugin
const ClearWebpackPlugin = require('clean-webpack-plugin');
module.exports=[
plugins:[
new ClearWebpackPlugin(['dist'])
]
];
复制代码
hot,开启模块热替换功能后,将在不刷新整个页面的状况下经过用新模块替换老模块来作到实时预览
inline,依赖一个注入页面里的代理客户端,去接收来自 DevServer的 命令并负责刷新网页的工做。
contentBase,配置 DevServerHTTP服务器的文件根目录
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ClearWebpackPlugin = require('clean-webpack-plugin');
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
const HappyPack = require('happypack');
module.exports = {
entry: './app/index/app.js', //支持多个参数,string|array|object
output: {
filename: ' [name].js', //输出文件名称
path: path.resolve(__dirname, './dist'), //输出文件的目标路径
publicPath: '/' //构建文件的输出目录
},
devServer: { //DevServer相关的配置
contentBase: path.join(__dirname, 'dist'),
compress: true, //压缩
port: 8888, //端口号
open: true, //第一次打开浏览器
hot: true, //是否监听
publicPath: "/" //访问的目录
},
module: {
rules: [{
test: /\.js$/,
use: [' babel-loader'],
parser: {
amd: true, //禁用AMD
commonjs: true, //禁用 CommonJS
system: false, //禁用 SystemJS
harmony: true, //禁用 ES6 import/export
requireinclude: false, //禁用require.include
requireEnsure: false, //禁用require.ensure
requireContext: false, //禁用require.context
browserify: false, //禁用 browserify requireJs : false, //禁用 requirejs:false
requireJs: false, //禁用 requirejs
}
},
{
// 用正则去匹配要用该 loader 转换的 CSS 文件
test: /\.css$/,
use: [{
loader: MiniCssExtractPlugin.loader,
}, {
loader: path.resolve('./loaders.js'),
options: {
test: 1
}
}, {
loader: 'css-loader?minimize',
}, {
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
require('postcss-cssnext')(),
require('cssnano')(),
require('postcss-sprites')()
]
}
}],
}, {
//图片处理
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000,
name: '[name].[ext]'
}
}]
}
]
},
resolve: {
modules: [
// 模块的查找目录
"node_modules",
path.resolve(__dirname, "app")
],
extensions: ['.js', '.json', '.vue', '.css'],
alias: { //模块别名列表
'module': 'new-module'
}
},
devtool: 'source-map', //sourcemap
plugins: [ //插件部分
new ClearWebpackPlugin(['dist']),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: `[name]_[contenthash:8].css`,
chunkFilename: '[name]_[contenthash:8].css'
}),
// 告诉webpack使用了哪些第三方库代码
new DllReferencePlugin({
// jquery 映射到json文件上去
manifest: require('./dill/jquery.manifest.json')
}),
new ParallelUglifyPlugin({
// 传递给 UglifyJS的参数以下:
uglifyJS: {
output: {
/*
是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,
能够设置为false
*/
beautify: false,
/*
是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,能够设置为false
*/
comments: false
},
compress: {
/*
是否在UglifyJS删除没有用到的代码时输出警告信息,默认为输出,能够设置为false关闭这些做用
不大的警告
*/
warnings: false,
/*
是否删除代码中全部的console语句,默认为不删除,开启后,会删除全部的console语句
*/
drop_console: true,
/*
是否内嵌虽然已经定义了,可是只用到一次的变量,好比将 var x = 1; y = x, 转换成 y = 5, 默认为不
转换,为了达到更好的压缩效果,能够设置为false
*/
collapse_vars: true,
/*
是否提取出现了屡次可是没有定义成变量去引用的静态值,好比将 x = 'xxx'; y = 'xxx' 转换成
var a = 'xxxx'; x = a; y = a; 默认为不转换,为了达到更好的压缩效果,能够设置为false
*/
reduce_vars: true
}
}
}),
//将js自动插入到html里
new HtmlWebpackPlugin({
template: './views/index.html',
filename: 'index.html',
}),
new webpack.HotModuleReplacementPlugin() //引入热更新插件
]
};
复制代码
优化主要是针对打包速度跟打包大小优化,主要包含如下方面
threads:开启几个子进程去处理这一类型的文件,默认是3个,必须整数
verbose:是否容许happypack输出日志,默认是true
threadpool:表明共享进程池,即多个happypack实例都使用同一个共享进程池中的子进程去处理任务,以防止资源占用过多
复制代码
介绍DllPlugin插件跟DllReferencePlugin插件
DllPlugin插件 : 用于打包出一个个单独的动态连接库文件 。 DllReferencePlugin 插件:用于在主要的配置文件中引入 DllP!ugin 插件打包好的动态连接库文件。
具体配置以下:
webpack.dll.config.js配置
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
// 入口文件
entry: {
// 项目中用到该两个依赖库文件
jquery: ['./libs/jquery'],
// echarts: ['echarts']
},
// 输出文件
output: {
// 文件名称
filename: '[name].dll.js',
// 将输出的文件放到dist目录下
path: path.resolve(__dirname, 'dill'),
/*
存放相关的dll文件的全局变量名称,好比对于jquery来讲的话就是 _dll_jquery, 在前面加 _dll
是为了防止全局变量冲突。
*/
library: '_dll_[name]'
},
plugins:[
// 使用插件 DllPlugin
new DllPlugin({
/*
该插件的name属性值须要和 output.library保存一致,该字段值,也就是输出的 manifest.json文件中name字段的值。
好比在jquery.manifest文件中有 name: '_dll_jquery'
*/
name: '_dll_[name]',
/* 生成manifest文件输出的位置和文件名称 */
path: path.join(__dirname, 'dill', '[name].manifest.json')
})
]
};
复制代码
webpack.config.js配置
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
{
plugins:
[
// 告诉webpack使用了哪些第三方库代码
new DllReferencePlugin({
// jquery 映射到json文件上去
manifest: require('./dill/jquery.manifest.json')
})
]
}
复制代码
1.1 webpack事件流
Webpack 就像一条生产线,要通过一系列处理流程后才能将源文件转换成输出结果。 这条生产线上的每一个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。 插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源作处理。 Webpack 经过 Tapable 来组织这条复杂的生产线。 Webpack 在运行过程当中会广播事件,插件只须要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运做。 Webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好。
1.2 webpack运行流程详解
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行如下流程。
流程图:
2.3 抽象语法树(AST)
在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每一个节点都表示源代码中的一种结构。之因此说语法是“抽象”的,是由于这里的语法并不会表示出真实语法中出现的每一个细节。好比,嵌套括号被隐含在树的结构中,并无以节点的形式呈现;而相似于 if-condition-then 这样的条件跳转语句,可使用带有两个分支的节点来表示。
实际上一段代码通过编译器的词分析、语法分析等阶段以后,会生成一个树状结构的“抽象语法树(AST)”,该语法树的每个节点都对应着代码当中不一样含义片断。
解释器是将AST翻译成目标语言并运行的工具。
插件代码
//@file: plugins/myplugin.js
class myPlugin {
constructor(options){
//用户自定义配置
this.options = options
console.log(this.options)
}
apply(compiler) {
console.log("This is my first plugin.")
}
}
module.exports = myPlugin
复制代码
webpack代码
const MyPlugin = require('./plugins/myplugin-4.js')
module.exports = {
......,
plugins: [
new MyPlugin("Plugin is instancing.")
]
}
复制代码
具体参数能够参考《深刻浅出webpack》
require (’ loader-utils ’);
callback
具体参数能够参考《深刻浅出webpack》
const loaderUtils = require('loader-utils');
module.exports = function (content) {
// 获取用户配置的options 同步
const options=loaderUtils.getOptions(this);
console.log('***options***',options);
this.callback(null,'{}'+content);
return '{};'+content;
}
复制代码
{
test: /\.js$/,
exclude: /node_modules/,
use: {
//这里是个人自定义loader的存放路径
loader: path.resolve('./loaders/index.js'),
options: {
test: 1
}
}
}
复制代码
webpack打包配置相对比较复杂,目前介绍应该能够满常规需求。
参考资料:
《深刻浅出webpack》
欢迎关注github