在接下来的几天里,我会持续不断的更新关于webpack4的系列文章,感兴趣的小伙伴,快快来围观
昨天
我们我们粗线条的讨论了webpack的几个核心概念,可以戳这里webpack4.x 准备起飞进行复习,说到webpack,node和npm就是我们绕不开的话题,关于npm的一些使用技巧,我之前整理了一篇文章,有兴趣的小伙伴可以点这里查看总结了一些关于npm的小技巧,好的,准备出发🚶
今天
从今天起我们使用webpack4,手动搭建一个vue项目,当然截止到今天2018-11-11,vue-cli已经更新到3.1.1了,大量简化了配置,我们在这里选择手动搭建,目的是了解webpack的具体配置,在以后的项目中,修改以及定制化一些配置,可以游刃有余。
项目初始化
⚠️Node版本依赖做了重新调整(可以参见更新日志)
官方建议node版本
"engines": {
"node": ">=6.11.5"
},
我当前node版本为8.9.0
好了,现在可以初始化项目了
npm init
全局安装 webpack
npm install webpack -g
然后本地安装相关依赖
npm i webpack webpack-cli webpack-dev-server -D
npm i vue vue-router axios -S
-D,-S
-D是–save-dev的缩写形式,-S是–save的缩写形式,i是install的缩写
安装完毕后,package.json多了下面两个对象
- dependencies
- devDependencies
–save参数表示将该模块写入dependencies属性,
–save-dev表示将该模块写入devDependencies属性。
dependencies是运行时依赖,devDependencies是开发时的依赖。
零配置
webpack4受Parcel打包工具启发,尽可能的让开发者运行项目的成本变低。为了做到0配置,webpack4不再强制需要 webpack.config.js 作为打包的入口配置文件了,它默认的入口为’./src/’和默认出口’./dist’,这无疑对小项目而言是福音。
你所需要做的是在你的项目里包含 ./src/index.js 文件。当在命令行里执行 webpack 命令时,webpack会将该文件作为项目的入口文件进行打包配置。
我们在这里不考虑零配置的情况,
配置webpack.config.js
我们先在根目录下创建webpack.config.js(后期会对目录结构做调整)
const webpack = require('webpack');
const path = require('path');
const config = {
}
module.exports = config;
path
在webpack里常见的一个功能path,我们简单介绍一些,已经了解的可以忽略
var path = require('path')
常用功能介绍
path.join() 方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径。
长度为零的 path 片段会被忽略。 如果连接后的路径字符串是一个长度为零的字符串,则返回 ‘.’,表示当前工作目录。
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'
path.join('foo', {}, 'bar');
// 抛出 'TypeError: Path must be a string. Received {}'
path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径。
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'
path.resolve('/foo/bar', '/tmp/file/');
// 返回: '/tmp/file'
path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
// 如果当前工作目录为 /home/myself/node,
// 则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'
__dirname
当前模块的文件夹名称。等同于 __filename 的 path.dirname() 的值。示例:运行位于 /Users/mjr目录下的example.js文件:node example.js
console.log(__dirname);
// Prints: /Users/mjr
console.log(path.dirname(__filename));
// Prints: /Users/mjr
__filename
当前模块的文件名称—解析后的绝对路径。
在主程序中这不一定要跟命令行中使用的名称一致。
例如:
在 /Users/mjr 目录下执行 node example.js
console.log(\__filename);
// Prints: /Users/mjr/example.js
console.log(__dirname);
// Prints: /Users/mjr
__dirname 返回绝对路径
再说mode模式
昨天我们探讨了一些mode的相关内容,今天我就详细讨论
这是在 Webpack4.0 之后新增的内容,目的就是减少部分属性的填写,使 Webpack 更容易上手,无形中减少了一些配置。
这个属性主要就是有两个值 production、development,主要就是声明当前是生产模式还是开发模式,默认为production模式,选择 none 也可以,但是会有一个 warning⚠️。
你可能会有一个疑问,这里只有生产环境和开发环境,那测试环境,预发布环境怎么处理呢?
答:这里所说的生产环境,就是除了开发环境(本地环境)以外的环境,只要往线上走,mode都是production
development 模式下,将侧重于功能调试和优化开发体验,包含如下内容:
- 浏览器调试工具
- 开发阶段的详细错误日志和提示
- 快速和优化的增量构建机制
production 模式下,将侧重于模块体积优化和线上部署:
- 开启所有的优化代码
- 更小的 bundle 大小
- 去除掉只在开发阶段运行的代码
- Scope hoisting 和 Tree-shaking
- 自动启用 uglifyjs 对代码进行压缩
Scope hoisting 是什么?
Scope Hoisting 可以让 Webpack 打包出来的代码文件更小、运行的更快,
它又译作 “作用域提升”,是在 Webpack3 中新推出的功能。
具体可以参考通过Scope Hoisting优化Webpack输出
Tree-shaking
简单说就是去除调js中没有使用的死代码
贴几个链接,可以看看具体介绍
你的Tree-Shaking并没什么卵用
Tree-Shaking性能优化实践 – 原理篇
不同的环境要使用不同的模式,为了提高代码复用,我门使用process这个全局变量来控制模式的转换,通过process.env.NODE_ENV 来判断当前是什么模式。
process.env 返回当前项目所在环境的一些信息,是一个对象。也可以对这个对象进行一些修改,比方说 process.env.foo = ‘bar’,
因为开发环境可能有多种,(本地开发,线上开发,线上测试,预发布,生产),所有我们添加一个判断,不是本地开发环境(development)的,全部指向mode的production模式,所以现在的 webpack.config.js 就变成了这样:
const webpack = require('webpack');
const path = require('path');
let env=process.env.NODE_ENV=="development"?"development":"production";
const config = {
mode: env,
}
module.exports = config;
mode也支持命令行
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}
entry
入口,一个总的js文件,就是你可以在这里引入你所需要的其他js文件,不管是 require 还是 import,Webpack 都是可以解析的,
entry的配置是必填的,不填就报错
context
context 是 webpack 编译时的基础目录,入口起点(entry)会相对于此目录查找。若不配置,默认为执行启动webpack时所在的当前工作目录,若想改变默认配
context 应该配置为绝对路径,假如入口起点为src/main.js,则可以配置:
module.exports ={
context: path.resolve('./src'),
entry: './main.js'
}
此时 entry 不能再配置为’./src/main.js’,因为 webpack 会相对于 context 配置的 src 目录区查找入口起点(main.js),而 main.js 就在此目录下,所以应当将 entry 配置为当前目录(./)。
entry 类型
entry接受三种形式的值:字符串,数组和对象
对象形式
entry: {
<key>: <value>
...
}
对象中的每一对属性对,都代表着一个入口文件,因此多页面配置时,肯定是要用这种形式的entry配置。
key
对象中key可以是简单的字符串,比如:’app’, ‘main’, ‘entry-1’等。并且对应着output.filename配置中的[name]变量
entry: {
'app-entry': './app.js'
},
output: {
path: './output',
filename: '[name].js'
}
上面的配置打包后生成:
key还可以是路径字符串。此时webpack会自动生成路径目录,并将路径的最后作为[name]。这个特性在多页面配置下也是很有用的
entry: {
'path/of/entry': './deep-app.js',
'app': './app.js'
},
output: {
path: './output',
filename: '[name].js'
}
value
value如果是字符串,而且必须是合理的noderequire函数参数字符串。比如文件路径:’./app.js'(require(‘./app.js’));比如安装的npm模块:’lodash'(require(‘lodash’))
entry: {
'my-lodash': 'lodash'
},
output: {
path: './output',
filename: '[name].js'
}
上面的配置打包后生成:
value如果是数组,则数组中元素需要是上面描述的合理字符串值。数组中的文件一般是没有相互依赖关系的,但是又处于某些原因需要将它们打包在一起。比如:
entry: {
vendor: ['jquery', 'lodash']
}
字符串entry
entry: './app.js'
等价于下面的对象形式:
entry: {
main: './app.js'
}
数组entry
entry: ['./app.js', 'lodash']
等价于下面的对象形式:
entry: {
main: ['./app.js', 'lodash']
}
chunk名称
webpack会为每个生成的Chunk取一个名称,Chunk的名称和Entry的配置有关:
- 如果entry是一个string或者array,就只会生成一个chunk,这个chunk的名称是main;
- 如果entry是一个object,就可能出现多个chunk,这时chunk的名称是object键值对里键的名称
配置动态Entry
假如项目里有多个页面需要为每个页面的入口配置一个entry,但这些页面数量可能会不断增长,这时entry的配置会受到其他因素的影响导致不能写成静态的值。解决办法就是把entry设置成一个函数去动态返回上面所说的配置:
//同步函数
entry: () => {
return {
a: './pages/a',
b: './pages/b'
}
}
//异步函数
entry: () => {
return new Promise((resolve) => {
resolve({
a: './pages/a',
b: './pages/b'
})
})
}
当结合 output.library 选项时:如果传入数组,则只导出最后一项。
总结
今天我们讨论了webpack4的两项配置
- mode模式
- entry 入口
明天继续,不见不散
最新评论
这小生活不错呀
不错,必须顶一下!
看着你还在坚持,很好
看来忙了也没时间更新博客了
NIce。学习了。。。。
网站不错!!!!
简洁实用,好文章!
不错,过来支持一下