一.webpack安装

  • 全局安装:npm install webpack webpack-cli -g

  • 局部安装:npm install webpack webpack-cli -d

二.webpack打包

2.1.项目目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
webpack
- src
- css
- common.css
- img
- 1.jpeg
- js
- 1.js
- 2.js
- index.js
- index.html
- package.json
- webpack.config.js
...

2.2.初次打包可能遇到的问题

2.2.1.问题

1
2
3
4
5
6
webpack : 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\webpack.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的about_Execution_Policies。
所在位置 行:1 字符: 1

+ webpack
+ + CategoryInfo : SecurityError: (:) [],PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess

2.2.2.解决方案

运行powershell(管理员身份),输入 set-ExecutionPolicy RemoteSigned ,选:A

1
2
3
4
5
6
PS C:\Users\Administrator> set-ExecutionPolicy RemoteSigned

执行策略更改
执行策略可帮助你防止执行不信任的脚本。更改执行策略可能会产生安全风险,如 https:/go.microsoft.com/fwlink/?LinkID=135170
中的 about_Execution_Policies 帮助主题所述。是否要更改执行策略?
[Y] 是(Y) [A] 全是(A) [N] 否(N) [L] 全否(L) [S] 暂停(S) [?] 帮助 (默认值为“N”):

2.3.webpack执行原理

webpack会从当前项目的文件夹下寻找src文件夹,把src文件夹下的index.js当做webpack打包的入口文件,打包完成后在当前项目下生成一个dist的目录文件夹,该文件夹中为打包后的文件;或者指定文件去打包,例如webpack ./src/index.js ./dist/main.js会把src文件夹下的index.js作为入口文件进行打包,打包之后生成一个dist文件夹,main.js作为打包之后的文件。(可以通过webpack.config.js进行自定义配置入口文件和打包后的文件等配置)

2.4.打包命令

2.4.1.注意

所有的命令都是在当前项目目录下执行

2.4.2.全局命令

webpack 或者 webpack ./src/index.js ./dist/main.js

2.4.3.局部命令

  • 先执行 npm init -y,在当前项目下会生成一个package.json的配置文件,该文件记录了当前项目下所需要的依赖 (如果输入npm init,需要输入当前项目的一些基本信息)

  • 再执行 npm install webpack webpack-cli -d,会按照package.json文件的配置,在当前项目下进行局部的安装webpack,生成一个node_modules的文件夹,需要执行在node_modules文件夹下的.bin文件夹下的webpack(三种命令任选其一)

  • 命令1:.\node_modules\.bin\webpack

  • 命令2:npx webpack npx会到当前目录的node_modules/.bin目录下查找对应的命令

  • 命令3:

    • 先在package.json文件中,在scripts中配置一个脚本命令"scripts": {"build": "webpack"}

    • 再执行 npm run build

三.webpack的基本配置

在当前项目下新建一个webpack.config.js文件,对当前项目进行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const path = require('path')	//导入node_modules中的path
module.exports = {
entry: './src/main.js', //打包入口文件
output: { //打包之后文件
path: path.resolve(__dirname, 'dist'), //动态获取当前的绝对地址,再拼接上'dist'
filename: 'bundle.js' //打包之后的文件名称
},
resolve: {
//resolve:解决
extensions: ['.js', '.css', '.vue'], //配置添加拓展名,在导入文件是无需再写文件拓展名
alias: { // 配置文件别名
'@': resolveApp('./src),
pages: resolveApp('./src/pages')
}
}
}

package.json

1
2
3
4
5
{
"scripts": {
"build": "webpack", //会优先的在本地找webpack命令
}
}

四.loader基本使用

4.1.样式的处理

具体使用参考官方文档:Loaders | webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)

4.1.1.less-loader

安装命令

1
2
3
4
5
npm install style-loader --save-dev	//将模块的导出作为样式添加到 DOM 中
npm install css-loader --save-dev //解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
npm install less-loader less --save-dev //加载和转译 LESS 文件
npm install sass-loader node-sass webpack --save-dev //加载和转译 SASS/SCSS 文件
(--save-dev -> -D) // 简写

基本配置

在使用其它loader之前需要先安装style-loader,然后在webpack.config.js中进行配置(例如配置less-loader

1
2
3
4
5
6
7
8
9
10
module.exports = {
module: {
rules: [{
test: /\.less$/,
use: [{loader: "style-loader"}, {loader: "css-loader"}, {loader: "less-loader"}] // 方式一
use: ["style-loader", "css-loader", "less-loader"] // 方式二
loader: "style-loader" // 方式三: 用于一个loader
}]
}
};

注意:使用多个loader时,是从后往前加载(先加载less-loader,再加载css-loader,最后加载style-loader

4.1.2.PostCSS

PostCSS是一个通过JavaScript来转换样式的工具,可以帮助我们进行一些CSS的转换和适配,比如自动添加浏览器前缀、css样式的重置,我们需要借助于PostCSS对应的插件。webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)

使用方式

  • 查找PostCSS在构建工具中的扩展,比如webpack中的postcss-loader
  • 选择可以添加你需要的PostCSS相关的插件 (使用了postcss-preset-env插件)

安装命令

1
2
npm install postcss-loader postcss -D	// 安装postcss-load
npm install postcss-preset-env -D // 安装post-css插件

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// webpack.config.js (方式一)
module.exports = {
module: {
rules: [{
test: /\.less$/,
use: [ "style-loader", "css-loader",
{
loader: "postcss-loader",
postcssOptions: {
plugins: [
[
'postcss-preset-env',
{
// 其他选项
},
],
]
}
}]
}]
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 方式二
// postcss.config.js
module.exports = {
plugins: [
[
'postcss-preset-env',
{
// 其他选项
},
],
],
};

// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
],
},
};

4.2.资源模块处理

资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。(使用图片加载实例)

官方文档:webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)

在 webpack 5 之前,通常使用:

资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:

  • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
  • asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
  • asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。

4.2.1.webpack5之前

具体使用参考官方文档:Loaders | webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)

安装命令

1
2
npm install --save-dev url-loader	// 像file loader一样工作,但如果文件小于限制,可以返回data URL
npm install --save-dev file-loader // 将文件发送到输出文件夹,并返回(相对)URL

基本配置

webpack.config.js中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif|jpeg|jfif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, //单位:字节(B)
//如果图片小于limit,会把图片转换为base64编码,超过limit会使用file-loader加载
name: 'imgs/[name].[hash:8].[ext]'
//会在发布的文件夹在生成一个imgs文件夹,打包之后的图片名为:原来的名称.哈希值取8位.拓展名
}
}
]
}
]
}
}

4.2.2.webpack5之后

具体参考文档:webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)

自定义文件的输出路径和文件名

  • 修改output,添加assetModuleFilename属性
  • 在Rule中,添加一个generator属性,并且设置filename

最常用的placeholder

  • [ext]: 处理文件的扩展名
  • [name]:处理文件的名称
  • [hash]:文件的内容,使用MD4的散列函数处理,生成的一个128位的hash值(32个十六进制) ([hash:6]: 取6位)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
assetModuleFilename: 'images/[hash:6][ext][query]' // 文件名方式一
},
module: {
rules: [
{
test: /\.(png|jpg|gif|jpeg|jfif)$/,
type: 'asset/resource',
generator: {
filename: 'images/[hash:6][ext][query]' // 文件名方式二
}
}
]
},
};

url-loader的limit效果

开发中往往小的图片需要转换,大的图片直接使用图片

小的图片转换base64之后可以和页面一起被请求,减少不必要的请求过程;大的图片也进行转换,反而会影响页面的请求速度

  • 将type修改为asset
  • 添加一个parser属性,并且制定dataUrlCondition条件,添加maxSize属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
rules: [
{
test: /\.(png|jpg|gif|jpeg|jfif)$/,
type: 'asset',
generator: {
filename: 'images/[hash:6][ext][query]'
},
parse: {
dataUrlCondition: {
maxSize: 100 * 1024
}
}
}
]

4.3.babel-loader

4.3.1.命令

具体使用参考官方文档:babel-loader | webpack 中文文档 | webpack 中文文档 | webpack 中文网 (webpackjs.com)

1
2
3
4
5
//webpack 3.x | babel-loader 8.x | babel 7.x
npm install babel-loader@8.0.0-beta.0 @babel/core @babel/preset-env

//webpack 3.x babel-loader 7.x | babel 6.x
npm install babel-loader babel-core babel-preset-env

4.3.2.配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
}

五.Vue的配置

5.1.Vue的安装

1
npm install vue --save

5.2.Vue的使用

5.2.1.vue版本问题

runtime-only => 代码中,不可以有任何的template

1
2
3
4
5
6
7
import Vue from 'vue'
import App from './App'

new Vue({
el: '#app',
render: h => h(App)
})

runtime-compiler => 代码中,可以有template,因为有compiler可以用于编译template

1
2
3
4
5
6
7
8
import Vue from 'vue'
import App from './App'

new Vue({
el: '#app',
components: { App },
template: '<App />'
})

需要在webpack.config.js中进行配置

1
2
3
4
5
6
7
8
9
module.exports = {
resolve: {
//resolve:解决
//alias:别名
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}

5.2.2.el 和 template的关系

template 会替换掉 el

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Vue from 'vue'

new Vue({
el: '#app',
template: `
<div>
<h2>{{title}}</h2>
<p>{{content}}</p>
</div>
`,
data: {
title: 'title',
content: 'content'
}
});

5.2.3.vue使用组件化的进一步简化

方式一:放在一个文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Vue from 'vue'

const App = {
template: `
<div>
<h2>{{title}}</h2>
<p>{{content}}</p>
</div>
`,
data() {
return {
title: 'title',
content: 'content'
}
}
}

new Vue({
el: '#app',
template: `<App />`,
components: {
App
}
});

方式二:抽离成一个单独的文件

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default {
template: `
<div>
<h2>{{title}}</h2>
<p>{{content}}</p>
</div>
`,
data() {
return {
title: 'title',
content: 'content'
}
}
}

index.js

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue'
import App from './app.js'

new Vue({
el: '#app',
template: `<App />`,
components: {
App
}
});

5.2.4.安装编译 .vue 文件的loader

5.2.4.1.安装

1
npm install --save-dev vue-loader vue-template-compiler

5.2.4.2.配置

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
use: [{
loader: "vue-loader"
}]
}]
}
};

此时遇到的问题

vue-loader的版本从14.x开始,需要再配置其它的插件

1
2
3
ERROR in ./src/vue/App.vue
Module build failed (from ./node_modules/vue-loader/dist/index.js):
Error: vue-loader requires @vue/compiler-sfc to be present in the dependency tree.

临时解决

package.json文件中配置低版本的vue-loader,然后执行npm install

1
2
3
4
5
{
"devDependencies": {
"vue-loader": "^13.0.0",
}
}

六.plugin的使用

6.1.添加版权

webpack.config.js

1
2
3
4
5
6
7
const webpack = require('webpack')

module.exports = {
plugins: [
new webpack.BannerPlugin('最终版权归coderxst所有')
]
}

打包之后在dist文件夹下生成一个main.js.LICENSE.txt的文件,生成的版权在文件头部出现

1
/*! 最终版权归coderxst所有 */

6.2.打包index.html文件

6.2.1.安装

1
npm install html-webpack-plugin --save-dev

6.2.2.配置

webpack.config.js

1
2
3
4
5
6
7
8
9
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: 'index.html'
})
]
}

最终会在dist文件夹下参照index.html的模板,生成一个index.html文件,并且会自动引入js文件

6.3.代码丑化压缩

6.3.1.安装

目前webpack已经集成压缩,可以不用安装UglifyJsWebpackPlugin,安装时需要安装低版本的(@1.1.1),不然报错

1
npm install uglifyjs-webpack-plugin --save-dev

6.3.2.配置

webpack.config.js

1
2
3
4
5
6
7
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

module.exports = {
plugins: [
new UglifyJsPlugin()
]
}

6.4.DefinePlugin的使用

DefinePlugin允许在编译时创建配置的全局常量,是一个webpack内置的插件(不需要单独安装)

webpack.config.js

1
2
3
4
5
6
7
8
9
10
const { DefinePlugin } = require('webpack')

module.exports = {
...
plugins: [
new DefinePlugin({
BASE_URL: '"./"'
})
]
}

七.本地服务器的搭建

7.1.命令

1
npm install webpack-dev-server --save-dev

7.2.配置

webpack.config.js

1
2
3
4
5
6
7
8
9
module.exports = {
devServer: {
contentBase: "./dist", //为哪一个文件夹提供本地服务,默认是根文件夹
inline: true, //页面实时刷新
open: true, //启用打开后,开发服务器将打开浏览器
port: 8080 //端口号(默认:8080)
historyApiFallback: true, //在SPA(单页面复应用程序)页面中,依赖HTML5的history模式
}
}

7.3.使用

方式一

直接运行node_modules中的devServer

1
./node_modules/.bin/devServer

方式二

package.json中配置

1
2
3
"scripts": {
"server": "webpack-dev-server"
}

八.webpack.config.js的分离

8.1.安装插件

1
npm install webpack-merge --save-dev

8.2.新建文件

在根目录下新建build文件夹,从中新建文件base.config.jsdev.config.jsprod.config.js,删除原来的webpack.config.js文件

8.3.配置

base.config.js

1
2
3
4
5
6
7
8
9
10
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'main.js'
},
......
}

dev.config.js

1
2
3
4
5
6
7
8
9
10
11
12
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config.js');

module.exports = webpackMerge.merge(baseConfig, {
devServer: {
contentBase: "./dist",
inline: true,
open: true,
port: 8080,
historyApiFallback: true,
}
})

prod.config.js

1
2
3
4
5
6
7
8
9
10
11
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config.js');

module.exports = webpackMerge.merge(baseConfig, {
plugins: [
new HtmlWebpackPlugin({
template: 'index.html'
})
]
})

package.json

1
2
3
4
5
6
{
"scripts": {
"build": "webpack --config ./build/prod.config.js",
"server": "webpack-dev-server --config ./build/dev.config.js"
}
}