陌上寒

陌上寒个人博客

从零搭建webpack4(mode和entry)

在接下来的几天里,我会持续不断的更新关于webpack4的系列文章,感兴趣的小伙伴,快快来围观
《从零搭建webpack4(mode和entry)》

昨天

我们我们粗线条的讨论了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为nodejs自带功能

常用功能介绍

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 模式下,将侧重于功能调试和优化开发体验,包含如下内容:

  1. 浏览器调试工具
  2. 开发阶段的详细错误日志和提示
  3. 快速和优化的增量构建机制

production 模式下,将侧重于模块体积优化和线上部署:

  1. 开启所有的优化代码
  2. 更小的 bundle 大小
  3. 去除掉只在开发阶段运行的代码
  4. Scope hoisting 和 Tree-shaking
  5. 自动启用 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'
}

上面的配置打包后生成:
《从零搭建webpack4(mode和entry)》
key还可以是路径字符串。此时webpack会自动生成路径目录,并将路径的最后作为[name]。这个特性在多页面配置下也是很有用的

entry: {
    'path/of/entry': './deep-app.js',
    'app': './app.js'
},
output: {
    path: './output',
    filename: '[name].js'
}

上面的配置打包后生成:
《从零搭建webpack4(mode和entry)》

value

value如果是字符串,而且必须是合理的noderequire函数参数字符串。比如文件路径:’./app.js'(require(‘./app.js’));比如安装的npm模块:’lodash'(require(‘lodash’))

entry: {
    'my-lodash': 'lodash'
},
output: {
    path: './output',
    filename: '[name].js'
}

上面的配置打包后生成:
《从零搭建webpack4(mode和entry)》
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的配置有关:

  1. 如果entry是一个string或者array,就只会生成一个chunk,这个chunk的名称是main;
  2. 如果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 入口

明天继续,不见不散

福利

整理了一套关于nodejs的教程,公众号后台回复“node教程三”即可领取
《从零搭建webpack4(mode和entry)》

参考链接
令人困惑的webpack之entry
webpack中文网
深入浅出webpack学习(2)–Entry

发表评论

电子邮件地址不会被公开。