webpack 本质上是一个打包工具,它会根据代码的内容解析模块依赖,帮助我们把多个模块的代码打包。

一切文件:JavaScript、CSS、SCSS、图片、模板,在 Webpack 眼中都是一个个模块,这样的好处是能清晰的描述出各个模块之间的依赖关系,以方便 Webpack 对模块进行组合和打包。 经过 Webpack 的处理,最终会输出浏览器能使用的静态资源。

entry

webpack 构建的入口entry,webpack 会读取这个文件,并从它开始解析依赖,在内部构件一个依赖图,这个依赖图会引用项目中使用到的各个模块,然后进行打包,生成一个或者多个 bundle 文件。

我们常见的项目中,如果是单页面应用,那么入口只有一个;如果是多个页面的项目,那么通常是一个页面会对应一个构建入口。

单⼊⼝:entry 是⼀个字符串,如下代码:

module.exports = {
entry: './src/index.js'
};

上述代码等价于:

// 上述配置等同于
module.exports = {
entry: {
main: './src/index.js'
}
}

多⼊口:entry 是⼀个对象,如下代码:

module.exports = {
entry: {
app: './src/app.js',
home: './src/home.js'
}
};

还有一种场景比较少用到,即是多个文件作为一个入口来配置,webpack 会解析多个文件的依赖然后打包到一起:

// 使用数组来对多个文件进行打包
module.exports = {
entry: {
main: [
'./src/foo.js',
'./src/bar.js'
]
}
}

动态 entry

const path = require('path');
const fs = require('fs'); // src/pages 目录为页面入口的根目录
const pagesRoot = path.resolve(__dirname, './src/pages');
// fs 读取 pages 下的所有文件夹来作为入口,使用 entries 对象记录下来
const entries = fs.readdirSync(pagesRoot).reduce((entries, page) => {
// 文件夹名称作为入口名称,值为对应的路径,可以省略 `index.js`,webpack 默认会寻找目录下的 index.js 文件
entries[page] = path.resolve(pagesRoot, page);
return entries;
}, {}); module.exports = {
// 将 entries 对象作为入口配置
entry: entries, // ...
};

output

output用来告诉 webpack 如何将编译后的文件输出到磁盘。webpack 构建生成的文件名、路径等都是可以配置的,在配置文件中使用 output 字段来进行设置:

module.exports = {
// ...
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
} // 或者使用 entry 的名称
module.exports = {
entry: {
main: './src/index.js' // main 为 entry 的名称
},
output: {
filename: '[name].js', // 使用 [name] 来引用 entry 名称,在这里即为 main
path: path.join(__dirname, '/dist/[hash]'),
// 路径中使用 hash,每次构建时会有一个不同 hash 值,可以用于避免发布新版本时浏览器缓存导致代码没有更新
// 文件名中也可以使用 hash
},
}

loader

我们在前端构建中会遇见需要使用各式各样的文件,例如 css 代码,图片,模板代码等。webpack 中提供一种处理多种文件格式的机制,便是使用 loader。我们可以把 loader 理解为是一个转换器,负责把某种文件格式的内容转换成 webpack 可以支持打包的模块。例如我们需要 css-loader 来处理 .css 文件(这里其实还需要 style-loader),最终把不同格式的文件都解析成 js 代码,以便打包后在浏览器中运行。

webpack 开箱即用只支持 JS 和 JSON 两种文件类型,通过 Loaders 去支持其它文件类型并且把它们转化成有效的模块,并且可以添加到依赖图中。

本身是一个函数,接受源文件作为参数,返回转换的结果。

常见的 Loaders 有哪些?

  • babel-loader:转换ES6、ES7等JS新特性语法
  • css-loader:支持.css文件的加载和解析
  • less-loader:将less文件转换成css
  • ts-loader:将TS转换成JS
  • file-loader:进行图片、字体等的打包
  • raw-loader:将文件以字符串的形式导入
  • thread-loader:多线程打包JS和CSS

下面我们来配置下处理css的loader以及ES6转ES5的loader,首先npm安装如下loader,

  • css-loader:npm i style-loader css-loader -D
  • babel-loader:npm install babel-loader @babel/core @babel/preset-env

babel的一系列工具链说明:

@babel/core:

@babel/core是babel的核心库,所有的核心Api都在这个库里,这些Api供babel-loader调用;

@babel/preset-env:

这是一个预设的插件集合,包含了一组相关的插件,Bable中是通过各种插件来指导如何进行代码转换。该插件包含所有es6转化为es5的翻译规则。

babel官网对此进行的如下说明:

Transformations come in the form of plugins, which are small JavaScript programs that instruct Babel on how to carry out transformations to the code. You can even write your own plugins to apply any transformations you want to your code. To transform ES2015+ syntax into ES5 we can rely on official plugins like@babel/plugin-transform-arrow-functions

大致即es6到es5的语法转换是以插件的形式实现的,可以是自己的插件也可以是官方提供的插件如箭头函数转换插件@babel/plugin-transform-arrow-functions。

由此我们可以看出,我们需要转换哪些新的语法,都可以将相关的插件一一列出,但是这其实非常复杂,因为我们往往需要根据兼容的浏览器的不同版本来确定需要引入哪些插件,为了解决这个问题,babel给我们提供了一个预设插件组,即@babel/preset-env,可以根据选项参数来灵活地决定提供哪些插件。为此,我们往往做如下配置:

@babel/polyfill:

@babel/preset-env只是提供了语法转换的规则,但是它并不能弥补浏览器缺失的一些新的功能,如一些内置的方法和对象,如Promise,Array.from等,此时就需要polyfill来做js得垫片,弥补低版本浏览器缺失的这些新功能。

我们需要注意的是,polyfill的体积是很大的,如果我们不做特殊说明,它会把你目标浏览器中缺失的所有的es6的新的功能都做垫片处理。但是我们没有用到的那部分功能的转换其实是无意义的,造成打包后的体积无谓的增大,所以通常,我们会在presets的选项里,配置"useBuiltIns": "usage",这样一方面只对使用的新功能做垫片,另一方面,也不需要我们单独引入import '@babel/polyfill'了,它会在使用的地方自动注入。

babel-loader:

以上@babel/core、@babel/preset-env 、@babel/polyfill其实都是在做es6的语法转换和弥补缺失的功能,但是当我们在使用webpack打包js时,webpack并不知道应该怎么去调用这些规则去编译js。这时就需要babel-loader了,它作为一个中间桥梁,通过调用babel/core中的api来告诉webpack要如何处理js。

@babel/plugin-transform-runtime:

polyfill的垫片是在全局变量上挂载目标浏览器缺失的功能,因此在开发类库,第三方模块或者组件库时,就不能再使用babel-polyfill了,否则可能会造成全局污染,此时应该使用transform-runtime。transform-runtime的转换是非侵入性的,也就是它不会污染你的原有的方法。遇到需要转换的方法它会另起一个名字,否则会直接影响使用库的业务代码,

故开发类库,第三方模块或者组件库时使用transform-runtime,平常的项目使用babel-polyfill即可.

详细可参考文章:

rules的配置如下:

module: {
rules:[
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
{
test: /\.jsx?$/, // 匹配文件路径的正则表达式,通常我们都是匹配文件类型后缀
exclude: /node_modules/, // 排除掉node_modules这个文件夹的js文件
include: [
path.resolve(__dirname,'src') // 指定哪些路径下的文件需要经过 loader 处理
],
use: { // 指定使用的 loader
loader: 'babel-loader', // babel-loader 可以使用 babel 来将 ES6 代码转译为浏览器可以执行的的 ES5 代码
options: {
presets: ['@babel/preset-env']
}
}
}
]
}

plugin

plugin 在 webpack 中的配置只是把实例添加到 plugins 字段的数组中。不过由于需要提供不同的功能,不同的 plugin 本身的配置比较多样化。

常用的plugin:

  • CommonsChunkPlugin:将chunks相同的模块代码提取成公共js,webpack4.x版本使用optimization.SplitChunks
  • cleanWebpackPlugin:清理构建目录
  • ExtractTextWebpackPlugin:将CSS从bundle文件里提取成一个独立的CSS文件(webpack3.x版本),webpack4.x版本使用mini-css-extract-plugin
  • CopyWebpackPlugin:将文件或者文件夹拷贝到构建的输出目录
  • HtmlWebpackPlugin:创建html文件去承载输出的bundle
  • UglifyjsWebpackPlugin:压缩JS
  • ZipWebpackPlugin:将打包出的资源生成一个zip包
const path = require('path');
module.exports = {
output: {
filename: 'bundle.js'
},
plugins: [
new HtmlWebpackPlugin({ // 放到plugins数组里
template: './src/index.html'
})
]
};

在 webpack 的构建流程中,plugin 用于处理更多其他的一些构建任务。可以这么理解,模块代码转换的工作由 loader 来处理,除此之外的其他任何工作都可以交由 plugin 来完成。

例如,使用 copy-webpack-plugin 来复制其他不需要 loader 处理的文件,只需在配置中通过 plugins 字段添加新的 plugin 即可:

npm install copy-webpack-plugin -D
# 插件通常为第三方的 npm package,都需要安装后才能使用
const CopyPlugin = require('copy-webpack-plugin');

module.exports = {
// ... plugins: [
new CopyPlugin([
{ from: 'src/public', to: 'public' },
]),
],
};

mode

mode,构建模式是 webpack v4 引入的新概念,用于方便快捷地指定一些常用的默认优化配置,mode 可以是 development,production,none 其中的一个,我们之前已经在配置文件中添加了相应的配置:

module.exports = {
mode: 'development', // 指定构建模式为 development
// ...
}

顾名思义,development 模式用于开发时使用,production 模式用于线上生产时使用,none 则是不需要任何默认优化配置时使用。

development 和 production 模式的区别:

  • 这两个模式会使用 DefinePlugin 来将 process.env.NODE_ENV 的值分别设置为 development 和 production,方便开发者在项目业务代码中判断当前构建模式。
  • production 模式会启用 TerserPlugin来压缩JS代码,让生成的代码文件更小。
  • development 模式会启用 devtools: 'eval' 配置,提升构建和再构建的速度。

前端构建基础配置

关联HTML

怎样将HTML引用路径和我们的构建结果关联起来,这个时候我们可以使用 html-webpack-plugin。

html-webpack-plugin 是一个独立的 package,在使用之前我们需要先安装它:

npm install html-webpack-plugin -D 

然后在 webpack 配置中,将 html-webpack-plugin 添加到 plugins 列表中:

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html', // 配置文件模板
}),
],
}

这样,通过 html-webpack-plugin 就可以将我们的页面和构建 JS 关联起来,回归日常,从页面开始开发。如果需要添加多个页面关联,那么实例化多个 html-webpack-plugin, 并将它们都放到 plugins 字段数组中就可以了。

构建 CSS

我们编写 CSS,并且希望使用 webpack 来进行构建,为此,需要在配置中引入 loader 来解析和处理 CSS 文件:

module.exports = {
module: {
rules: {
// ...
{
test: /\.css/,
include: [
path.resolve(__dirname, 'src'),
],
use: [
'style-loader',
'css-loader',
],
},
},
}
}

上面配置的两个loader的作用:

  • css-loader 负责解析 CSS 代码,主要是为了处理 CSS 中的依赖,例如 @import 和 url() 等引用外部文件的声明;
  • style-loader 会将 css-loader 解析的结果转变成 JS 代码,运行时动态插入 style 标签来让 CSS 代码生效。

如果需要单独把 CSS 文件分离出来,我们需要使用 mini-css-extract-plugin 插件。

v4 版本之后才开始使用 mini-css-extract-plugin,之前的版本是使用 extract-text-webpack-plugin。

如下例子:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
// ...
module: {
rules: [
{
test: /\.css/i,
use: [
// 因为这个插件需要干涉模块转换的内容,所以需要使用它对应的 loader
MiniCssExtractPlugin.loader,
'css-loader',
],
},
],
}, plugins: [
new MiniCssExtractPlugin({
filename: '[name].css' // 这里也可以使用 [hash]
}), // 将 css 文件单独抽离的 plugin
]
};

在上述使用 CSS 的基础上,通常我们会使用 Less/Sass 等 CSS 预处理器,webpack 可以通过添加对应的 loader 来支持,以使用 Less 为例

less-loader 只是 webpack 的转换器,启动 Less 你还需要安装 less 自身,同样地,sass-loader 也是这般。

在 webpack 配置中,添加一个配置来支持解析后缀为 .less 的文件:

module.exports = {
// ...
module: {
rules: [
{
test: /\.(less|css)$/,
use: [
// 因为这个插件需要干涉模块转换的内容,所以需要使用它对应的 loader
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
],
},
],
},
// ...
}

处理图片文件

在前端项目的样式中总会使用到图片,虽然我们已经提到 css-loader 会解析样式中用 url() 引用的文件路径,但是图片对应的 jpg/png/gif 等文件格式,webpack 处理不了。是的,我们只要添加一个处理图片的 loader 配置就可以了,现有的 file-loader 就是个不错的选择。

file-loader 可以用于处理很多类型的文件,它的主要作用是直接输出文件,把构建后的文件路径返回。配置很简单,在 rules中添加一个字段,增加图片类型文件的解析配置:

module.exports = {
// ...
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {},
},
],
},
],
},
}

使用babel

Babel 是一个让我们能够使用 ES 新特性的 JS 编译工具,我们可以在 webpack 中配置 Babel,以便使用 ES6、ES7 标准来编写 JS 代码。

module.exports = {
// ...
module: {
rules: [
{
test: /\.jsx?/, // 支持 js 和 jsx 文件,使用 react 时需要
include: [
path.resolve(__dirname, 'src'), // 指定哪些路径下的文件需要经过 loader 处理
],
use: {
loader: 'babel-loader', // 指定使用的 loader
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
}

webpack笔记-webpack基础用法(二)的更多相关文章

  1. react基础用法二(组件渲染)

    react基础用法二(组件渲染) 如图所示组件可以是函数 格式:function 方法名(){ return <标签>内容</标签>} 渲染格式: <方法名 />  ...

  2. Java并发编程笔记之基础总结(二)

    一.线程中断 Java 中线程中断是一种线程间协作模式,通过设置线程的中断标志并不能直接终止该线程的执行,而是需要被中断的线程根据中断状态自行处理. 1.void interrupt() 方法:中断线 ...

  3. Bootstrap fileinput:文件上传插件的基础用法

    官网地址:http://plugins.krajee.com/ 官网提供的样例:http://plugins.krajee.com/file-input/demo 基础用法一 导入核心CSS及JS文件 ...

  4. webpack笔记二 管理资源

    webpack笔记二 管理资源 webpack最出色的功能之一就是除了引入JavaScript,还可以通过loader引入任何其它类型的文件. 加载CSS 为了在JavaScript模块中import ...

  5. Webpack笔记(二)——搭建React开发环境

    前几天一直在学习webpack,总算比之前学习的时候有了点收获,所以在昨天发布了一篇webpack入门笔记,今天继续使用webpack练了练手,搭建了一个React开发环境,如果还不熟悉的童鞋可以看一 ...

  6. Webpack笔记(一)——从这里入门Webpack

    准备了挺久,一直想要好好深入了解一下Webpack,之前一直嫌弃Webpack麻烦,偏向于Parcel这种零配置的模块打包工具一些,但是实际上还是Webpack比较靠谱,并且Webpack功能更加强大 ...

  7. webpack学习笔记—webpack安装、基本配置

    文章结构: 什么是webpack? 安装webpack 'webpack基本配置 一.什么是webpack? 在学习react时发现大部分文章都是react和webpack结合使用的,所以在学reac ...

  8. 初识webpack——webpack四个基础概念

    前面的话 webpack是当下最热门的前端资源模块化管理和打包工具.它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源.当webpack处理应用程序时,它会递归地构建一个依赖关系图表 ...

  9. 基于webpack的React项目搭建(二)

    前言 前面我们已经搭建了基础环境,现在将开发环境更完善一些. devtool 在开发的过程,我们会经常调试,so,为了方便我们在chrome中调试源代码,需要更改webpack.config.js,然 ...

  10. 深入浅出的webpack构建工具---DevServer配置项(二)

    深入浅出的webpack构建工具---DevServer配置项(二) 阅读目录 DevServer配置项 1. contentBase 2. port 3. host 4. headers 5. hi ...

随机推荐

  1. 全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解-提高代码可读性的利器

    全网最适合入门的面向对象编程教程:07 类和对象的 Python 实现-类型注解-提高代码可读性的利器 摘要: 本文对类型注解的定义.使用原因进行了基本介绍,同时对使用 typing 模块实现类型提示 ...

  2. Mysql密码安全策略修改

    Mysql5.7默认有密码安全策略,密码安全级别要求比较高,在测试环境中使用起来不方便,本经验将介绍如何修改Mysql的密码安全策略,解决ERROR 1819错误. 1:首先使用root用户连接mys ...

  3. 全网最适合入门的面向对象编程教程:18 类和对象的 Python 实现-多重继承与 PyQtGraph 串口数据绘制曲线图

    全网最适合入门的面向对象编程教程:18 类和对象的 Python 实现-多重继承与 PyQtGraph 串口数据绘制曲线图 摘要: 本文主要介绍了 Python 中创建自定义类时如何使用多重继承.菱形 ...

  4. <el-table-column prop="item_no" label="料号"/>设置最小宽度

    可以通过min-width属性来设置el-table-column的最小宽度.以下是一个示例: <template> <el-table :data="tableData& ...

  5. oeasy教您玩转vim - 6 - # 保存修改

    另存与保存 回忆上节课内容 我们上次进入了插入模式 从正常模式,按<kbd>i</kbd>,进插入模式 从插入模式,按<kbd>ctrl</kbd>+& ...

  6. oeasy教您玩转vim - 40 - # 复制粘贴

    ​ 复制粘贴 回忆上节课内容 我们上次的内容是粘贴 小写p意味着在光标下面或者后面粘贴 大写P意味着在光标上面或者前面粘贴 p的意思是放上去,就是put 把什么放上去呢? 把 reg 中 " ...

  7. [oeasy]教您玩转python - 0006 - 自由软件运动和开源运动

    ​ 顺序执行 回忆上次内容 上次写了10000行代码 10000行代码 都是写在明面上的 人家一下载​​py​​ 文件 就能看个明明白白 修改或者运行程序都很方便 这程序全都这么公开出来 大家随意修改 ...

  8. vue项目读取文件问题

    问题:在src\assets资源目录存放非图片文件无法获取. 解决:将非图片文件存放到public上,读取的时候路径不带public. 例如:资源的相对路径为:public/roboto/1Kg.wo ...

  9. ABC362

    A link 判断即可... 点击查看代码 #include<bits/stdc++.h> using namespace std; int r,g,b; string c; signed ...

  10. Windows下UI自动化工具Inspect

    windows系统下的UI自动化工具Inspect是包含在WindowsSDK包里的,所以需要先下载SDK包,然后在SDK包路径下找到Inspect工具并打开使用就可以了. 官网下载链接:https: ...