写在前面,这是我个人对webpack中一些常见的问题做的总结。小白一枚,不具有深度参考价值、
webpack是什么?和Gulp相比有什么区别?
webpack可以看做是模块打包机,是一个前端资源打包工具,它将根据模块的依赖关系进行分析,然后按照指定的规则生成对应的静态资源。
为什么要使用webpack?
- 前端模块化
- css预处理器
- …
与Gulp的区别
Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。
gulp可以进行js,html,css,img的压缩打包,是自动化构建工具,可以将多个js文件或是css压缩成一个文件,并且可以压缩为一行,以此来减少文件体积,加快请求速度和减少请求次数;并且gulp有task定义处理事务,从而构建整体流程,它是基于流的自动化构建工具。
webpack的工作方式是:把项目当成一个整体,通过一个给定的入口文件,webpack将从这个文件开始找到项目的依赖文件,用loader处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件
loader和plugin的使用和区别
loader
通过使用不同的loader,webpack有能力调用外部的脚本或工具,实现对不同格式的文件的处理,比如转换scss为css或者吧es6、es7转换成浏览器兼容的js文件。对于react而言,合适的Loaders可以把React的中用到的JSX文件转换为JS文件。
常见的loader有style-loader、css-loader、less-loader、babel-loader、url-loader等
Loaders需要单独安装并且需要在webpack.config.js中的modules关键字下进行配置,Loaders的配置包括以下几方面:
- test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
- loader:loader的名称(必须)
- include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
- query:为loaders提供额外的设置选项(可选)
在webpack.config.js中单独配置modules
module:{
// 配置所有第三方loader模块
rules:[
{test:/\.css$/,use:['style-loader','css-loader']},
{test:/\.less$/,use:['style-loader','css-loader','less-loader']},
// 当图片大小大于或者等于给定值得时候,则不会被转为base64格式。如果图片大小小于这个值,则会被转为base64格式
// {test:/\.(jpg||png||jpeg||gif||bmp)$/,use:'url-loader?limit=52451&name=[hash:8]-[name].[ext]'}//处理图片路径的
{test:/\.(jpg||png||jpeg||gif||bmp)$/,use:'url-loader?limit=52451'},
{test:/\.(ttf||eot||svg||woff||woff2)$/,use:'url-loader'},//处理字体文件的loader
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/},
{test:/\.vue$/,use:'vue-loader'},//处理vue文件的loader
]
}
插件(Plugins)
插件是来拓展Webpack功能的,它会在整个构建过程中生效,执行相关的任务。
loader和plugins常常被弄混,但是他们完全不同,主要区别在于,loader是打包构建过程中用来处理源文件的(JSX、Scss、Less)一次处理一个,插件并不直接操作单个文件,它对整个构建过程起作用。
常用的插件有
html-webpack-plugin
在内存中,根据指定的模板页面生成一份内存中的首页,同时将打包好的bundle.js注入到页面底部
优化插件
- OccurenceOrderPlugin::为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
- UglifyJsPlugin:压缩JS代码;
- ExtractTextPlugin:分离CSS和JS文件
需要在webpack.config.js中引入插件,然后再单独配置plugins
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
plugins:[
// 所有webpack插件的配置节点
new htmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html'),
filename:'index.html'//设置生成的页面名称
}),
new VueLoaderPlugin()
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin("style.css")
]
npm中-S和-D的区别
- npm install xxx -S,也就是 npm install module_name --save 写入dependencies
- npm install xxx -D,也就是 npm install module_name --save-dev 写入devDependencies
devDependencies ,是我们开发的时候需要用到的一些包(大部分都是-D,各种loader,包括gulp、webpack以及webpack-dev-server),只需要用于开发阶段,真正打包上线的时候并不需要这些包,因为这些工具只是你用来打包代码的,是用来识别特定文件以及代码,帮助我们生产最终文件的
dependencies,这个则是需要发布到生产环境中的(vue全家桶,前端UI),就比如你要跑一个基于vue的项目,所以需要vue.js来支持,而这个vue.js文件就需要跟随项目到最终的生产环境
webpack打包原理
首先回顾几个核心的概念
- entry :入口,webpack执行构建的第一步就是从入口开始(一般是src的main.js)
- module: 模块,webpack中一切皆模块,一个模块对应一个文件,webpack从配置的entry开始递归寻找所有依赖的模块
- Chunk:代码块,一个Chunk由多个模块组合而成,用于代码合并与分割
- Loader:模块转换器,用于把模块原内容按照需求转换成新内容
- Plugin:扩展插件,在Webpack构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情
webpack只是一个打包模块的机制,只是把依赖的模块转化成可以代表这些包的静态文件。webpack就是识别你的 入口文件,识别你的模块依赖,来打包你的代码。
webpack做的就是分析代码。转换代码,编译代码,输出代码。
webpack中每个模块有一个唯一的id,是从0开始递增的。整个打包后的bundle.js是一个匿名函数自执行。参数则为一个数组。数组的每一项都为个function。function的内容则为每个模块的内容,并按照require的顺序排列。
打包流程
1、初始化:启动构建,读取与合并配置参数,加载plugin,实例化Compiler
2、编译:从entry出发,针对每个module单串行调用对应的loader,再找到module依赖的module,递归的进行编译处理
3、输出:对编译后的module组合成chunk,转换成文件,输出到文件系统。
webpack打包优化
体积大小优化
1、开启webpack4.x mode的生产模式
webpack4.x以后有一个mode选项,可以配置两种打包环境,一个是开发环境development一个是生产环境production
打包的时候使用webapck --mode=production命令打包,这个是代码压缩过的
或者在webpack.config.js中进行配置
mode:‘production’,//产品模式会被压缩,开发模式不会被压缩
2、提取公共依赖
抽离的公共依赖满足的条件:
(1)体积过大
(2)不经常更新
(3)依赖较多
常见的满足这类条件的包有:react,react-dom,redux,react-redux,jquery等
使用 CommonsChunkPlugin 插件,将多个 js 文件进行提取,建立一个独立的文件。这个文件包含一些共用模块,浏这样览器只在刚开始的时候加载一次,便缓存起来供后续使用。而不用每次访问一个新界面时,再去加载一个更大的文件。
entry:{
app:'./entry',
vendor:['react','other-lib'],
},
plugins:[
new Webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
}),
]
3、优化devtool中的source-map
dev-tool 提供了很多种选项,用来增强我们 debug 的能力,我们熟知的有: source-map , inline-source-map , cheap-source-map 等等。如果你的文件在打包之后突然变成好几M,那么不用想,肯定是因为 source-map 的原因。 source-map 在开发阶段确实很好用,调试起来很方便,但是在生产环境下就没必要部署了。 建议在 prod 环境下关闭 source-map
4、使用CDN引入
webpack 提供Externals的方法,可以通过外部引用的方法,引入第三方库
index.html中:
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
webpack.config.js中配置:
module.exports = {
externals: {
jquery: 'jQuery'
}
};
5、使用 UglifyJSPlugin 压缩
通过 UglifyJSPlugin 可以压缩我们的 *.js 文件。 安装方法: npm install uglifyjs-webpack-plugin --save-dev 。
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins: [
new UglifyJSPlugin({
parallel: 4,
uglifyOptions: {
output: {
comments: false,
beautify: false,
},
compress: {
warnings: false
},
},
cache: true,
}),
]
6、开启gzip压缩等
我们使用 compression-webpack-plugin 插件进行压缩。 安装: npm install compression-webpack-plugin --save-dev
const CompressionPlugin = require("compression-webpack-plugin");
plugins:[
new CompressionPlugin({
asset: '[path].gz[query]', //目标资源名称。[file] 会被替换成原资源。[path] 会被替换成原资源路径,[query] 替换成原查询字符串
algorithm: 'gzip',//算法
test: new RegExp(
'\\.(js|css)$' //压缩 js 与 css
),
threshold: 10240,//只处理比这个值大的资源。按字节计算
minRatio: 0.8//只有压缩率比这个值小的资源才会被处理
})
]
速度优化
1.优化loader配置
缩小文件匹配范围(include/exclude)
通过排除node_modules下的文件 从而缩小了loader加载搜索范围 高概率命中文件
2、resolve优化配置
2.1 优化模块查找路径 resolve.modules
Webpack的resolve.modules配置模块库(即 node_modules)所在的位置,在 js 里出现 import ‘vue’ 这样不是相对、也不是绝对路径的写法时,会去 node_modules 目录下找。但是默认的配置,会采用向上递归搜索的方式去寻找,但通常项目目录里只有一个 node_modules,且是在项目根目录,为了减少搜索范围,可以直接写明 node_modules 的全路径;同样,对于别名(alias)的配置,亦当如此:
const path = require('path');
function resolve(dir) { // 转换为绝对路径
return path.join(dirname, dir);
}
resolve: {
modules: [ // 优化模块查找路径
path.resolve('src'),
path.resolve('node_modules') // 指定node_modules所在位置 当你import 第三方模块时 直接从这个路径下搜索寻找
]
}
2.2 resolve.alias 配置路径别名
创建 import 或 require 的路径别名,来确保模块引入变得更简单。配置项通过别名来把原导入路径映射成一个新的导入路径 此优化方法会影响使用Tree-Shaking去除无效代码。
例如,一些位于 src/ 文件夹下的常用模块
alias: {
Utilities: path.resolve(dirname, 'src/utilities/'),
Templates: path.resolve(dirname, 'src/templates/')
}
2.3resolve.extensions
当引入模块时不带文件后缀 webpack会根据此配置自动解析确定的文件后缀
后缀列表尽可能小
频率最高的往前放
导出语句尽可能带上后缀
resolve: {
extensions: ['.js', '.vue']
}
现在,替换「在导入时使用相对路径」这种方式,就像这样:
import Utility from '../../utilities/utility';
你可以这样使用别名:
import Utility from 'Utilities/utility';
3、ParallelUglifyPlugin
这个插件可以帮助有很多入口点的项目加快构建速度。把对JS文件的串行压缩变为开启多个子进程并行进行uglify。
cnpm i webpack-parallel-uglify-plugin -D
参考资料
https://www.jianshu.com/p/42e11515c10f
https://www.jianshu.com/p/e24ed38d89fd
https://www.jb51.net/article/135991.html
https://segmentfault.com/a/1190000011138081?utm_source=tag-newest
webpack原理(真的超级全面了,收藏留着以后慢慢看)
https://blog.csdn.net/weixin_40811829/article/details/88599201