webpack的基本使用


前话

  • 本质上,webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle

安装

npm init -y
npm install  webpack webpack-cli --save-dev

入口(entry)

  • 入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的
  • 默认值是 ./src/index.js,但你可以通过在 webpack configuration 中配置 entry 属性,来指定一个(或多个)不同的入口起点

.gitignore

node_modules

src\title.js

module.exports = 'zsy'

src\index.js

  • 这个文件依赖 title.txt,但是webpack内部会处理这些文件之间的依赖,构建一个依赖图
let title = require('./title.js');
console.log(title)

webpack.config.js

const path = require('path');
module.exports = {
  mode: 'development',
  // 入口写法一:字符串
  // entry: './src/index.js',

  // 入口写法二:数组形式
  // entry: ['./src/index1.js', './src/index2.js'],  // 其实还是单入口,即只有一个入口,只不过有两个文件而已

  // 入口写法三:对象形式
  entry: {
    main: './src/index.js',
    // main: ['./src/index1.js', './src/index2.js'],  // 效果与上面的数组形式是一样的
  },
};

package.json

{
  // ......
   "scripts": {
    "build": "webpack"
  },
  // ...... 
}

输出(output)

  • output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件
  • 主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。

webpack.config.js

// ......
module.exports = {
  // ......
  output: {
    // 表示要 向dist文件下写入 main.js 文件,下面代码的配置都是默认值,不写也是会默认打包到 dist/main.js
    path: path.resolve(__dirname, 'dist'), 
    filename: 'main.js'
  }
};

多入口打包

  • webpack.config.js
module.exports = {
  // ...... 
  entry: {
    index1: './src/index1.js',
    index2: './src/index2.js',
  },
  output: {
    path: path.resolve(__dirname, 'dist'), 
    filename: '[name].js'  // 这个name是对应entry 对象中的key
  }
};

entry和output的路径规则

  • entry和output都可以写成绝对路径
  • entry还可以写成相对路径,但是output则不能
  • 因为我们执行命令时,肯定是在项目的目录下执行,所以入口可以写成相对的,但是打包后的文件可以放到硬盘的任意位置,所以output不能写成相对路径的

loader

  • webpack 只能理解 JavaScriptJSON 文件,也就是在js文件中,webpack只认识 require(‘xxx.js’) 或 require(‘xxx.js’) 这两种文件,比如不认识 xx.txt 文件
  • 使用loader后,会将不认识的文件转为js文件,如 txt 文件转为 js文件
  • loaderwebpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中

webpack.config.js

npm i raw-loader -D
// ......
module.exports = {
  // ......
  module: {
    rules: [
      { 
        // 当遇到以 .txt 结尾的文件时,会交给 raw-loader 去处理
        test: /\.txt$/, 
        use: [ 'raw-loader' ]  // raw-loader 意思是 '原生loader'
      }
    ]
  }
};
  • src\name.txt
    ‘peiqi’

  • src\index.js

let name = require('./name.txt')
console.log('我的名字', name.default)  // webpack打包后,外层会包一层,所以取 default 属性才是真的值
  • dist\index.html
<body>
  <!-- 引入打包后的文件 -->
    <script src="./main.js"></script>
</body>
  • 然后直接访问该 html 页面,查看控制台

补充面试题:执行 npm run build 干了什么

    1. 找当前项目的package.json 下面的scripts 下面的 build这个key,拿到其对应的值,即 webpack,这是shell脚本
    1. 然后执行该shell脚本,即webpack命令
    • 2.1 第一步先看 node_modules.bin 下是否存在 webpack.cmd,如果存在则执行它
    • 2.2 如果不存在,则会执行全局目录下的 webpack.cmd,(可以通过在cmd窗口中执行 npm root -g,会输出npm的全局目录,然后去该路劲看看或者在这儿:【C:\Users\a1371\AppData\Roaming\npm】),可以查看到是否有 webpack.cmd,没有的话可以通过 执行 npm i webpack-cli -g 进行安装
    • 如果还是没有则就报错了
    1. 如果找到全局的webpack.cmd那么就执行,会读取当前目录下的 webpack.config.js 进行编译

chunk和assets和file的概念

  • index.js(依赖title.js) 和 title.js 都叫做一个个的模块,多个模块打包合在一起叫做 代码块,也就是 chunk
  • 代码块经过编译打包后变成 资源assets,资源是由key-value组成,key就是main.js,value就是里面的内容字符串
  • 资源经过输出,最后会写入硬盘,就变成了file文件
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-STsWmf7W-1662776328652)(./images/2.png)]

插件(plugin)

  • webpack打包会经过很多流程,在过程中我们可以使用 插件 做更多的事情
  • loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量
  • 在前面的代码中,在 dist\index.html中我们手动引入了打包的js文件,我们使用 HtmlWebpackPlugin 插件,这样我们就不需要手动写了

src\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>webpack5</title>
</head>
<body>
</body>
</html>

webpack.config.js

npm i html-webpack-plugin -D
// ......
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  // ......
  plugins: [
    // HtmlWebpackPlugin 插件会向输出目录dist下写入一个 【index.html】 文件,并且将打包后的文件,即main.js 自动引入到index.html去
    new HtmlWebpackPlugin({
        template: './src/index.html', // 指定使用的模板页面
        filename: 'index.html'  // 打包后的模板页面名称
    })
  ]
};
  • 此时我们直接把旧的 dist文件删掉,重新打包试试

模式(mode)

  • 日常的前端开发工作中,一般都会有两套构建环境
  • 一套开发时使用,构建结果用于本地开发调试,不进行代码压缩,打印 debug 信息,包含 sourcemap 文件
  • 一套构建后的结果是直接应用于线上的,即代码都是压缩后,运行时不打印 debug 信息,静态文件不包括 sourcemap
  • webpack 4.x 版本引入了 mode 的概念
  • 当你指定使用 production mode 时,默认会启用各种性能优化的功能,包括构建结果优化以及 webpack 运行性能优化
  • 而如果是 development mode 的话,则会开启 debug 工具,运行时打印详细的错误信息,以及更加快速的增量编译构建
选项描述
development会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin
production会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin

环境差异

  • 开发环境

    • 需要生成 sourcemap 文件
    • 需要打印 debug 信息
    • 需要 live reload 或者 hot reload 的功能
  • 生产环境

    • 可能需要分离 CSS 成单独的文件,以便多个页面共享同一个 CSS 文件
    • 需要压缩 HTML/CSS/JS 代码
    • 需要压缩图片
  • 其默认值为 production

区分环境

  • --mode用来设置模块内的process.env.NODE_ENV
  • --env用来设置webpack配置文件的函数参数
  • cross-env用来设置node环境的process.env.NODE_ENV
  • DefinePlugin用来设置模块内的全局变量
命令行配置1
  • webpack(构建)的mode默认为production
  • webpack serve(开发服务器)的mode默认为development
  • 可以在模块内通过process.env.NODE_ENV获取当前的环境变量,无法在webpack配置文件中获取此变量

比如在package.json:

"scripts": {
  // 当不在webpack.config.js设置mode,那么当执行 npm run build,则默认都是生产环境(production)
  "build": "webpack",

  // webpack4 是要执行 webpack-dev-server
  // webpack5直接执行 webpack serve 就ok了
  // 不过还是需要安装  webpack-dev-server 的,即:npm i webpack-dev-server -D
  // 当不在webpack.config.js设置mode,那么当执行 npm run start,则默认都是生产环境(production)
  "start": "webpack serve"
},

src\index.js

// 查看当前是开发环境还是生产环境
console.log(process.env.NODE_ENV);// development | production

webpack.config.js

  • 在该配置文件中是拿不到 process.env.NODE_ENV 的
console.log('NODE_ENV',process.env.NODE_ENV);// undefined
命令行配置2
  • 在package.json 中指定生产环境或开发环境
"scripts": {
  "build": "webpack --mode=production",
  "start": "webpack --mode=development serve"
},
命令行配置
  • 无法在模块内通过 process.env.NODE_ENV 访问
  • 可以通过webpack 配置文件中中通过函数获取当前环境变量
"scripts": {
  // 通过 --env=production 这样设置,那么在 webpack.cconfig.js 中不能 打印出 process.env.NODE_ENV,在 src/index.js 等模块中也是不能 打印出来的
   "build": "webpack --env=production",
   "start": "webpack serve --env=development",
}

index.js

// 通过 --env=production 这样设置,在模块内拿不到 
console.log(process.env.NODE_ENV);// undefined

webpack.config.js

// 通过 --env=production 这样设置,在 webpack.config.js 也拿不到 
console.log('NODE_ENV',process.env.NODE_ENV);// undefined
// 但是如果配置文件导出一个函数,那么 webpack.config.js 就可以拿到了 
module.exports = (env,argv) => {
  console.log('env',env);// development | production
  return {
    // 写入口 出口等配置项
    // ......
  }
};
mode配置
  • 和命令行配置2一样
module.exports = {

  /**
  "scripts": {
    "build": "webpack --mode=production",
    "start": "webpack --mode=development serve"
  },
   */ 
  // 如下配置的优先级低于上面的配置方式:
  mode: 'development' 
}
DefinePlugin
  • DefinePlugin 这是定义全局变量的插件
  • 能设置全局变量(不是window),所有模块都能读取到该变量的值
  • 可以在任意模块内通过 process.env.NODE_ENV 获取当前的环境变量
  • 但无法在node环境(webpack 配置文件中)下获取当前的环境变量
// ......
const webpack = require('webpack')
module.exports = ()=>{
  console.log('env', env);
  let isDevelopment = env.development
  let isProduction = env.production
  return {
    plugins:[
    // ......
    new webpack.DefinePlugin({
      // 这里必须使用 JSON.stringify 包一层
      // 否则打包后是变量,而不是字符串
        'process2.env2.NODE_ENV2':JSON.stringify(isDevelopment? 'development': 'production'),
      })
    ]   
  }
}
  
npm run start 和 npm run test 的run 都可以直接省略


index.js

console.log('process.env.NODE_ENV2',process2.env2.NODE_ENV2);//  production

webpack.config.js

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// undefined
console.log('NODE_ENV',NODE_ENV);// error !!!
cross-env
  • 安装:
npm i cross-env -D
  • 只能设置node环境下的变量NODE_ENV
    package.json
"scripts": {
  "build": "cross-env NODE_ENV=production webpack",  // 执行这个命令, NODE_ENV对应得值 production就会传给 process.env.NODE_ENV,那么 webpack.config.js就可以拿到,不会直接传给 js模块
  "start": "cross-env NODE_ENV=development webpack serve"    
}

webpack.config.js

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// 执行npm run build,输出:process.env.NODE_ENV production

module.exports = (env)=>{ 
  return {
    mode: process.env.NODE_ENV,  // 也给到这儿
    // ......
    plugins:: [
      new webpack.DefinePlugin({
        // 下面的 NODE_ENV 只是一个名字,可以随便取,然后在js文件中直接取该名字就可以得到 process.env.NODE_ENV
        'peiqi': JSON.stringify(process.env.NODE_ENV)  // 也给到这儿
      })
    ]
  }
}

src\index.js:

console.log('mode设置的是:', process.env.NODE_ENV)  // 输出:production
console.log('DefinePlugin设置的:', peiqi)  // 输出:production

dotenv

安装:

# dotenv-expand: 增强版的 .env,在.env文件可以使用模板字符串的形式
npm i dotenv-expand -D

# 普通版的 .env,在.env文件只能设置 key-value
npm i dotenv -D
  • 使用dotenv,只需要将程序的环境变量配置写在.env文件中

项目根目录 \ .env

MONGODB_HOST=localhost
MONGODB_PORT=27017
MONGODB_DB=test
MONGODB_URI=mongodb://${MONGODB_HOST}:${MONGODB_PORT}/${MONGODB_DB}

项目根目录 \ testEnv.js :

const dotenv = require('dotenv')
const dotenvExpand = require('dotenv-expand')

const dotenvFile = '.env';
let myEnv = dotenv.config({
    path: dotenvFile,
})

dotenvExpand.expand(myEnv)

console.log(process.env.MONGODB_HOST); // 输出:localhost
console.log(process.env.MONGODB_PORT); // 输出:27017
console.log(process.env.MONGODB_DB); // 输出:test
console.log(process.env.MONGODB_URI); // 输出:mongodb://localhost:27017/test
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值