entry表示入口,一般是一个字符串,表示入口文件的路径。如果是多入口就需要将entry拥有很多键值对的对象,属性名就是每个入口的名字,值是每个入口的路径。
// 单入口
entry: './src/main.js'
// 多入口
entry: {
main: './src/main.js',
other: './src/other.js'
}
output出口的配置一般配置产出文件的名字和路径。如果入口配置是多入口,那出口文件也肯定是一一对应的。
const path = require('path')
output: {
filename: '[name].js' // [name]表示生成文件名字与入口设置的名字相同
path: path.resolve(__dirname, 'dist')// 表示最后输出的目录是当前项目的dist目录下,__dirname是一个在node.js下面的一个表示当前项目路径的常量
}
配置好了entry和output之后。如果你的项目只有js文件,那么,它已经可以正常运行了。通过运行webpack命令
// --progress 显示打包进度百分比
// --stats=varbose 显示打包全日志,还有其它属性值,normal默认日志显示设置,只显示部分主要日志。errors-info只在报错时显示错误日志
npx webpack --stats=varbose --progress
假设你项目入口是main.js文件。它引用了a.js和b.js两个文件。在运行上面的命令之后,在项目的dist文件生成了一个新的main.js文件。这个文件就是打包之后的产物。
我们知道了webpack的第一个作用:打包。打包各种类型的文件。
上面我们只有js文件,未免太简单了些。其实webpack可以还可以打包CSS,图片,Vue等各种类型的文件
下面我们添加处理vue文件的打包方式。处理vue类型的文件,需要专门的vue-loader,配置到规则里面。
module: {
rules: [
{
// 处理.vue后缀的文件
test: /\.vue$/,
use: 'vue-loader'
},
]
}
这样就可以了吗?答案是还不够。还需要在插件里面添加一个对应的VueLoaderPlugin插件。
const { VueLoaderPlugin } = require('vue-loader')
module: {
rules: [
{
// 处理.vue后缀的文件
test: /\.vue$/,
use: 'vue-loader'
},
]
},
plugins: [
new VueLoaderPlugin() // ???
]
这样才可以完整的处理vue类型的文件。它其它是将.vue文件变成了三个不同类型文件,其中的script和templte都会被处理成js,style标签的部分则会由vue-style-loader去处理。
其中 vue-style-loader
是对.vue文件里面css部分进行处理,对所有样式添加scoped字段,使之只在组件div下生效。不进行这层的处理,样式就全部都成了全局样式。
module: {
rule: [
{
// 处理css文件
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
]
}
css-loader和style-loader的区别:css-loader
会把css文件打包成commonjs模块。style-loader
则是主要把js里面的样式资源插入到html的style标签里面,让样式生效。
module: {
rule: [
{
test: /\.(png|svg|jpe?g|gif)$/,
use: {
loader: 'file-loader',
options: {
name:'assets/[name].[ext]',
}
}
}
]
}
使用 file-loader
来处理各种后缀的图片,png,svg,jpg,gif格式的图片。这个加载器的主要作用是解决开发和打包时,图片路径不一致,导致的图片不能访问的问题。也就是解决路径问题。
还有一个loader是 url-loader
,这两个加载器的区别是:url-loader 主要作用是为了减少http请求。会将图片编码成dataURI(base64等)打包到文件里面,这样直接访问dataURI就可以显示图片了,也就不用再请求了。
当然也不能全部图片都进行编码,大尺寸的图片编码非常消耗性能,还是应该使用http请求。所以 url-loader 里面有一个参数limit用来限制可以进行编码的图片大小,小于这个尺寸的会将图片进行编码,而超过这个尺寸的图片还是会使用 file-loader 进行处理。也就是说 url-loader 其实是包含有 file-loader 的。
// url-loader的使用方法
module: {
rule: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000, // 单位是:B(字节)
}
}
]
}
目前我们打包好的文件,直接开始就可以看到源码,基本就是webpakc把不同文件使用胶水代码合并在了一起。
所以不能直接使用在生产环境中,需要将代码压缩,使其基本不可读。保护代码的安全。
而且压缩代码,文件的体积也会变小,有利于网络传输。
optimization: {
minimize: true // 开启默认压缩配置
minimizer: [ // 自定义压缩配置(如果需要的话)
new TerserPlugin({
......
})
]
}
具体配置用到的时候再说。
optimization: { // 这个配置项是对打包流程进行优化的配置
splitChunks: { //
cacheGroups: { //
// 外部也可以进行配置,当内部配置不与外部配置冲突的时候,使用内部内部配置,不冲突时,共用。
commons: {
test: /[\\/]node_modules[\\/]/, // 配置是一个正则,所以引入来自node_modules文件夹里面的文件,都会打包成一个vendors.js文件
name: "vendors", // 打包之后,文件的名字
chunks: "initial" // 不同导入方式进行配置
}
}
}
}
参数chunks有三个值,分别是initial:对异步或者同步导入的模块分别进行打包,打包到不同的文件里面。async:不配置时的默认值,只会将异步导入的模块进行单独打包。all:无论异步还是同步加载的模块,都会单独进行打包,并且最后都会打包到同一个文件里面去。
chunks的参数提到了异步和同步导入模块。那么怎么算是同步导入,怎么又算是异步导入呢?
import 'xxx'
或者 require('xxx')
import('xxx')
或者 require('xxx', () => { yyy })
而我们常用的 import xxx from 'path'
这种写法也是同步导入的。
参考MDN上说的,只有 import('xxx')
这种像是函数一样的调用是异步导入模块的,其它都是同步的。而且 import('xxx')
会返回一个Promise对象去操作异步返回的模块对象。
import('XXX')
.then(module => { // 像这样去操作异步返回的模块
......
})
.catch(error => {
......
})
这种import异步导入模块的常见用法是在routes.js路由里面。
{
path: '',
component: () => import('XXX'), // 异步加载路由
children: [
......
]
}
同步导入写法 import 'xxx'
它的作用是运行模块(而不是导入模块)。使用模块的副作用。比如使用这样方法导入CSS,运行模块会进行样式的添加,本身就是一种副作用。而不是希望得到CSS文件里面暴露的模块(这也是不可能的)。