【webpack 系列】基础篇
Webpack 基础篇
基本概念
Webpack 是一个现代 JavaScript 应用程序的静态模块打包器。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
四个核心概念
- 入口(Entry): 构建
Webpack内部依赖图的入口模块 - 输出(Output): 输出
Webpack打包好的Bundles - Loader: 加载器,
Webpack原生只能解析JavaScript文件,Loader让webpack拥有了加载和解析非JavaScript文件的能力。 - 插件(Plugins): 扩展
Webpack的功能,让Webpack具有更多的灵活性。在Webpack运行的生命周期中会广播出许多事件,Plugin可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果。
Webpack 基础配置
本文所有代码可以查看github。
初始化项目
新建一个文件夹 webpack-demo,在该目录中使用 npm init -y 进行项目初始化。
mkdir webpack-demo && cd webpack-demo
npm init -y
运行以下命令安装最新版本或特定版本
npm i -D webpack
npm i -D webpack@<version>
如果你使用 webpack 4+ 版本,你还需要安装 CLI。
npm i -D webpack-cli
npm i -D为npm install --save-dev的缩写,安装一个用于开发环境的安装包npm i -S为npm install --save的缩写,安装一个要打包到生产环境的安装包
现在安装的 webpack 版本号是:
├── webpack@4.42.1
└── webpack-cli@3.3.11
新建 src/index.js 文件:
// src/index.js
class HelloComponent {
constructor (content = '') {
this.content = content;
this.render();
}
render () {
const element = document.createElement('div');
element.innerHTML = this.content;
document.body.appendChild(element);
}
}
new HelloComponent('hello webpack');
现在可以直接执行 npx webpack,默认是 production 模式。
也可以在 package.json 中的 scripts 里配置一个 build 命令,模式指定为 production。
webpack 默认会将 ./src/index.js 作为入口文件,默认打包到 dist/main.js。
// ...
"scripts": {
"build": "webpack --mode=production"
}
// ...
通过 npm run build 可以执行我们定义的命令,这是可以多了 dist/main.js 文件,这就是打包之后的 js 代码。
webpack 配置文件
上面例子中使用的是 webpack 的默认配置,下面我们来定义更加丰富的自定义配置。
根目录下新建 webpack.config.js 文件
const path = require('path');
module.exports = {
mode: 'development', // 模式
entry: path.resolve(__dirname, 'src/index.js'), // 入口文件
output: {
path: path.resolve(__dirname, 'dist'), // 输出目录
filename: 'bundle.js' // 输出文件名
}
}
更改我们的 build 命令,指定 webpack 按照我们的配置文件来打包文件
"scripts": {
"build": "webpack --config webpack.config.js"
}
执行 npm run build 可以看到,dist 目录下新增了 bundle.js 文件。并且 bundle.js 是在开发模式下打包的,可以看到更多的信息。
html-webpack-plugin 插件
现在我们已经有了打包好的 js 文件了,需要添加个 html 文件来引入这个 js 文件在浏览器查看效果了。
在实际开发中,为了避免每次修改打包的 js 文件被浏览器缓存而看不到最新的代码,我们会给打包文件加上 hash,相当于这个文件的版本号。这样每次修改后打包的 js 文件名都会不同,如果人工去修改 html 中的 js 文件名就太麻烦了,我们可以借助 html-webpack-plugin 插件来自动完成这些事情。
安装 html-webpack-plugin
npm i -D html-webpack-plugin
新建 public/index.html 文件,修改我们的 webpack.config.js
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//...
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'public/index.html'), // 指定模板文件,不指定会生成默认的 index.html 文件
filename: 'index.html' // 打包后的文件名
})
]
}
执行 npm run build 可以看到 dist 目录下新增了 index.html 文件,并且自动将打包好的 bundle.js 文件通过 script 标签引入了。
webpack-dev-server 开发工具
现在可以通过浏览器直接打开 dist/index.html 查看了,但是这样每次改完代码我们都需要手动 npm run build 一下,这样太麻烦了。
我们可以借助 webpack-dev-server 来解决这个问题。webpack-dev-server 会提供了一个简单的 web 服务器,并且能够实时重新加载。
安装 webpack-dev-server
npm i -D webpack-dev-server
修改 package.json 文件
// package.json
"scripts": {
"dev": "webpack-dev-server --config webpack.config.js",
"build": "webpack --config webpack.config.js"
}
npm run dev 之后,默认会在 localhost:8080 下建立服务,通过访问这个地址可以访问到 dist 目录下的文件。
可以在 webpack.config.js 对 devServer 进行配置
// webpack.config.js
module.exports = {
// ...
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: '9000', // 指定端口,默认是8080
compress: true // 是否启用 gzip 压缩
}
//...
}
关于 webpack-dev-server 更多的配置可以点击查看。
mode
我们在 package.json 定义了两条命令,但是 mode 都为 development。我们可以通过设置 process.env.NODE_ENV 的值来区分开发还是生产环境。
我们需要安装一下 cross-env, 来实现跨平台设置 NODE_ENV
npm i -D cross-env
// package.json
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js"
}
修改 webpack.config.js
// webpack.config.js
const isProduction = process.env.NODE_ENV == 'production';
module.exports = {
mode: isProduction ? 'production' : 'development', // 模式
// ...
}
设置 mode 的不同值可以启用相应模式下的 webpack 内置的优化
| 选项 | 描述 |
|---|---|
development |
会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。 |
production |
会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin. |
用 babel 向后兼容 js 语法
现在我们的代码虽然已经完成了打包,但是并没有被转义为低版本的代码。我们需要通过 Babel 来将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
安装 babel-loader
npm i -D babel-loader
此外我们还需要安装以下依赖
npm i -D @babel/core @babel/preset-env @babel/plugin-transform-runtime
npm i -S @babel/runtime @babel/runtime-corejs3
在 webpack.config.js 配置 babel-loader
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.jsx?$/,
use: ['babel-loader'],
exclude: /node_modules/ // 排除 node_modules 目录
}
]
}
// ...
}
建议给 loader 指定 include 或是 exclude,排除一些不需要编译的目录可以提高编译效率,比如 node_modules 目录。
有两种方式配置 babel
- 通过
.babelrc文件配置
根目录下新建一个.babelrc文件,配置如下:
// .babelrc
{
"presets": ["@babel/preset-env"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
- 在
webpack中配置babel
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"],
plugins: [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
},
exclude: /node_modules/
}
]
}
}
通过执行 npm run dev, 我们查看 http://localhost:9000/bundle.js 发现已经是转义之后的低版本代码了。
使用 source map
当 webpack 打包源代码时,会很难追踪到错误和警告在源代码中的原始位置。为了更容易地追踪错误和警告,JavaScript 提供了 source map 功能,将编译后的代码映射回原始源代码。
在开发环境中,可以设置 devtool 值为 inline-source-map,生产环境设置为 none 或者 source-map。
// webpack.config.js
const isProduction = process.env.NODE_ENV == 'production';
module.exports = {
// ...
devtool: isProduction ? 'source-map' : 'inline-source-map',
}
使用 source-map 最终会单独打包出一个 .map 文件,我们可以根据报错信息和 map 文件定位到源代码。
但是一般不会直接将 .map 文件部署到 CDN,而是将 .map 文件传到错误监控系统,以便我们可以解析到出错的源码位置。
处理样式文件
webpack 只能处理 js 文件,如果要处理 css 需要借助 loader。
如果是 .css,我们需要的 loader 有: style-loader、css-loader,考虑到兼容性问题,还需要 postcss-loader、autoprefixer
如果是 .less, 还需要 less-loader、less
如果是 .sass 的话,还需要 sass-loader、node-sass
安装相应的依赖
npm i -D style-loader css-loader postcss-loader autoprefixer less-loader less sass-loader node-sass
webpack.config.js 添加 css、less、sass loader
// webpack.config.js
module.exports = {
// ..
module: {
rules: [
// ...
{
test: /\.(c|le)ss$/,
use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'],
exclude: /node_modules/ // 排除 node_modules 目录
},
{
test: /\.sass$/,
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
exclude: /node_modules/ // 排除 node_modules 目录
}
]
}
}
根目录新建 postcss.config.js
// postcss.config.js
module.exports = {
plugins: [
// 兼容浏览器,添加前缀
require('autoprefixer')({
overrideBrowserslist: [
"Android 4.1",
"iOS 7.1",
"Chrome > 31",
"ff > 31",
"ie >= 8"
// 'last 10 versions', // 所有主流浏览器最近10版本用
],
grid: true
})
]
}
配置完成,新建几个文件测试一下
/* src/index.css */
div {
width: 200px;
height: 100px;
display: flex;
}
// src/index.less
@color: yellow;
body {
background: @color;
display: flex;
}
// src/index.sass
$text-color: orange;
div
color: $text-color;
display: flex;
再在入口文件中引入三个文件
// src/index.css
import './index.css';
import './index.less';
import './index.sass';
我们可以看到样式生效并且 flex 也自动加上浏览器前缀了。
需要注意的是 loader 的执行顺序是从右向左执行的,执行顺序为:
less-loader/sass-loader => postcss-loader => css-loader => style-loader
less-loader处理编译.less文件,将其转为csssass-loader处理编译.sass文件,将其转为csspostcss-loader和autoprefixer,自动生成浏览器兼容性前缀css-loader处理css中的@import、url(...)等语句style-loader动态创建style标签,将css插入到head中
处理图片、字体等媒体文件
我们可以使用 url-loader 或者 file-loader 来处理本地的资源文件。
file-loader 就是将文件在进行一些处理后(主要是处理文件名和路径、解析文件 url),将文件移动到输出的目录中,同时在 require 文件的地方会返回文件的绝对路径。
url-loader一般与 file-loader 搭配使用,功能与 file-loader 类似,如果文件小于限制的大小,则会返回 base64 编码。
需要同时安装 file-loader 和 url-loader
npm i -D file-loader url-loader
配置 webpack.config.js
// webpack.config.js
module.exports = {
// ..
module: {
rules: [
// ...
{
test: /\.(jpe?g|png|gif|webp|svg|eot|ttf|woff|woff2)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 10240, // 10K 资源大小小于 10K 时,将资源转换为 base64,超过 10K,将图片拷贝到 dist 目录
name: '[name]_[hash:6].[ext]', // 设置文件名,默认情况下,生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名
outputPath: 'assets', // 输出目录
esModule: false // 表示是否使用es6模块的导出,默认是启用的
}
}
],
exclude: /node_modules/
}
]
}
}
我们修改 src/index.sass 文件
// src/index.sass
$text-color: orange;
div
color: $text-color;
display: flex;
background: url('../images/author.jpg');
修改了配置文件,我们重新 npm run dev 一下,可以看到图片地址已经被替换了
npm run build 可以看到 dist/assets 有这个文件
注意此时如果需要在 html 文件中引用这个图片需要这样写
<body>
<img src="<%= require('../images/author.jpg') %>">
</body>
最终打包之后的路径是
打包前清空 dist 目录
我们修改文件打包之后,生成的 hash 值和之前 dist 中的不一样,会导致 dist 下的文件越来越多,所以我们需要在打包前先清空 dist 目录。
安装 clean-webpack-plugin
npm i -D clean-webpack-plugin
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
//...
plugins: [
// ...
new CleanWebpackPlugin()
]
}
这样每次打包前就会自动清除 dist 目录下的文件了。
最后
通过上面的实践,我们对 webpack 的基础配置有了一个初步的了解。本文所有代码可以查看github。
后续将会继续推出 webpack 系列的其他内容哦~
喜欢本文的话点个赞吧~
更多精彩内容,欢迎关注微信公众号~
【webpack 系列】基础篇的更多相关文章
- iOS系列 基础篇 03 探究应用生命周期
iOS系列 基础篇 03 探究应用生命周期 目录: 1. 非运行状态 - 应用启动场景 2. 点击Home键 - 应用退出场景 3. 挂起重新运行场景 4. 内存清除 - 应用终止场景 5. 结尾 本 ...
- iOS系列 基础篇 04 探究视图生命周期
iOS系列 基础篇 04 探究视图生命周期 视图是应用的一个重要的组成部份,功能的实现与其息息相关,而视图控制器控制着视图,其重要性在整个应用中不言而喻. 以视图的四种状态为基础,我们来系统了解一下视 ...
- iOS系列 基础篇 05 视图鼻祖 - UIView
iOS系列 基础篇 05 视图鼻祖 - UIView 目录: UIView“家族” 应用界面的构建层次 视图分类 最后 在Cocoa和Cocoa Touch框架中,“根”类时NSObject类.同样, ...
- iOS系列 基础篇 06 标签和按钮 (Label & Button)
iOS系列 基础篇 06 标签和按钮 (Label & Button) 目录: 标签控件 按钮控件 小结 标签和按钮是两个常用的控件,下面咱们逐一学习. 1. 标签控件 使用Single Vi ...
- iOS系列 基础篇 07 Action动作和输出口
iOS系列 基础篇 07 Action动作和输出口 目录: 1. 前言及案例说明 2. 什么是动作? 3. 什么是输出口? 4. 实战 5. 结尾 1. 前言及案例说明 上篇内容我们学习了标签和按钮 ...
- iOS系列 基础篇 08 文本与键盘
iOS系列 基础篇 08 文本与键盘 目录: 1. 扯扯犊子 2. TextField 3. TextView 4. 键盘的打开和关闭 5. 打开/关闭键盘的通知 6. 键盘的种类 7. 最后再扯两句 ...
- iOS系列 基础篇 09 开关、滑块和分段控件
iOS系列 基础篇 09 开关.滑块和分段控件 目录: 案例说明 开关控件Switch 滑块控件Slider 分段控件Segmented Control 1. 案例说明 开关控件(Switch).滑块 ...
- Java多线程系列--“基础篇”11之 生产消费者问题
概要 本章,会对“生产/消费者问题”进行讨论.涉及到的内容包括:1. 生产/消费者模型2. 生产/消费者实现 转载请注明出处:http://www.cnblogs.com/skywang12345/p ...
- Java多线程系列--“基础篇”04之 synchronized关键字
概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...
- Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式
概要 本章,我们学习“常用的实现多线程的2种方式”:Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程 ...
随机推荐
- 在idea下遇到的问题汇总(间接性更新)
在idea下遇到的问题汇总(间接性更新) tomcat下的jsp代码问题: 在idea的环境下,遇到jsp代码.符号失效,首先需要考虑到jar包没有引入,情况如图: 这种情况是因为jar包没有导入进去 ...
- Ubuntu gnome 美化与个别组件安装
1. 安装 gnome 工具 sudo apt install gnome-tweaks# 打开时中文直接选择 "优化" 即可 1.1. gnome 官网 # https://ex ...
- 华为的Java面试题,仅供参考。
IP地址的编码分为哪俩部分? IP地址由两部分组成,网络号和主机号.不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位. 2.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该 ...
- python3.5以及scrapy,selenium,等 安装
一.python3.5安装和配置 在安装的时候无意间发现了,python3.6没有给我自定义安装的机会,直接就C盘见:因此我选择了python3.5.<安装部分跳过,至于一条吃过痛苦的建议:不要 ...
- PHPRAP v1.0.6 发布,修复因php7.1版本遗弃mcrypt扩展造成安装失败的BUG
PHPRAP,是一个PHP轻量级开源API接口文档管理系统,致力于减少前后端沟通成本,提高团队协作开发效率,打造PHP版的RAP. 更新记录 [修复]修复因php7.1版本遗弃mcrypt扩展造成安装 ...
- iOS应用构建与部署小结
注:本文首发于我的个人博客:https://evilpan.com/2019/04/06/ios-basics/ 上篇文章介绍了Objective-C的基本概念,本文就来接着看如何创建我们的第一个简单 ...
- Python 存储数据到json文件
1 前言 很多程序都要求用户输入某种信息,程序一般将信息存储在列表和字典等数据结构中. 用户关闭程序时,就需要将信息进行保存,一种简单的方式是使用模块json来存储数据. 模块json让你能够将简单的 ...
- vmware企业虚拟化平台vSphere管理与配置
├─1-CCIE-DC课程介绍.avi ├─2-vSphere-简介.avi ├─3-vSphere-新功能介绍.avi ├─4-vSphere-授权介绍.avi ├─5-vSphere-课程拓扑介绍 ...
- VUE二 生命周期详解
vue官网对vue生命周期的介绍 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.销毁等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实 ...
- 什么是Servlet?Servlet的周期和方法
1.什么是Servlet? Servlet是运行在web服务器或应用服务器的程序,它是作为来自web浏览器或其他http客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层! 2.Servl ...