webpack:快速搭建环境

webpack:快速搭建环境

@jarringslee

文章目录

webpack搭建环境

快速搭建开发环境

问题:在之前若要修改代码,需要重新打包才能查看,效率很低

开发环境: 配置 webpack-dev-sever 快速开发应用程序

**注意:只能用于开发环境,不能用于生产环境 **

作用:启动web服务,自动检测代码变化,热更新到网页

热更新:代码一变化或修改,立即自动替换并更新到网页中,无需手动刷新网页。

步骤:

  1. 下载 webpack-dev-sever 到当前项目

    bash 复制代码
    npm i webpack-dev-server --save-dev
  2. 在 webpack.config.js 中设置开发模式 mode:'development 并在 package,json 配置自定义命令 "dev" : "webpack serve --open"

    js 复制代码
    // webpack.config.js
    
     module.exports = {
      mode: 'development',
       entry: {
    		//......
       },
       plugins: [
         new HtmlWebpackPlugin({
          // title: 'Output Management', 把这行修改为(可选):
          title: 'Development',
         }),
       ],
       output: {
       	  // ......
       },
     };
    json 复制代码
    // package.json
    
    "scripts": {
        "build": "webpack"
        "dev" : "webpack serve --open"  // 新加这一行
      },
  3. 运行环境命令。

    bash 复制代码
    npm run dev

注意:

  1. webpack-dev-server借助http模块创建8080默认web服务。即创建了http://localhost:8080/login.html 静态界面
  2. 默认以 public 文件夹作为服务器的根目录
  3. webpack-dev-server根据配置,打包相关代码在内存当中,以 output.path 作为服务器的根目录

可以在public文件夹下新建html文件index.html

接下来,我们在index.js文件中编辑或添加的信息会实时反映在网页中。

两种打包模式

打包模式 即告知webpack使用相应的内置模块进行优化

分类:

  • 开发模式 development 用于本地开发

    特点:调试代码、实时加载、模块热替换等。

  • 生产模式 production 用于打上线

    特点:压缩代码、资源优化、更轻量等。

设置方式:

  • 方法一:在webpack.config.js文件中设置mode选项。

    js 复制代码
    export default {
        // 配置开发环境:设置打包模式为开发模式
        mode: 'development',
        ......
        }
  • 方法二:在package.json命令行设置 --mode 参数

    json 复制代码
      "scripts": {
        "build": "webpack --mode=production",
        "dev": "webpack serve --mode=development"
      },
  • 推荐使用命令行文件。如果两者都有设置,json文件中命令行里的优先级大于配置文件的优先级,会覆盖配置文件

打包模式的应用

需求:在开发模式下用 style-loader 内嵌模块,在生产模式下提取css代码

方案1: 用webpack.config.js配置文件导出函数,但是局限性很大(只接受两种模式)

方案2:借助 cross-nev(跨平台通用)包命令,设置参数区分环境

使用软件包 cross-env 进行打包

步骤:

  1. 下载cross-env软件包到当前项目

    bash 复制代码
    npm i cross-env --save--dev
  2. 配置自定义命令,传入参数名和值(会绑定到process.env对象下)

    json 复制代码
    "scripts": {
        "build": "cross-env NODE_ENV=production webpack --mode=production",
        "dev": "cross-env NODE_ENV=development webpack serve --open --mode=development"
      }

    其中,"NODE_ENV=development" 等号后面的名字是自己起的

  3. 在配置文件 webpack.config.js 中区分不同环境使用不同配置

    js 复制代码
    rules: [
                // css规则
                {
                    test: /\.css$/i,
                    // use: ['style-loader', 'css-loader'],
                    use: [process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader'],
                },
        	    // less规则
                {
                    test: /\.less$/i,
                    use: [
                        // compiles Less to CSS
                        // 'style-loader',   不能和minicssextractplugin混用
                        process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
                        'css-loader',
                        'less-loader',
                    ],
                },
        	// ......
        ]
  4. 打包并观察模式的区别

  • 方法三:配置不同的 webpack.config.js (使用多种模式差异性较大的情况)

注入环境变量

环境变量的主要作用:根据不同的环境执行不同的配置

需求:在前端项目写一个打印语句,开发模式下打印语句生效,生产模式下打印语句失效

问题: cross-env 设置的只在nodejs环境生效,前端代码无法访问process.env.NODE_ENV

解决方法:使用webpack内置的DefinePlugin插件

DefinePlugin 允许在 编译时 将你代码中的变量替换为其他值或表达式。这在需要根据开发模式与生产模式进行不同的操作时,非常有用。例如,如果想在开发构建中进行日志记录,而不在生产构建中进行,就可以定义一个全局常量去判断是否记录日志。这就是 DefinePlugin 的发光之处,设置好它,就可以忘掉开发环境和生产环境的构建规则。

作用:在编译时,将前端代码中匹配的变量名,替换为值或表达式

步骤:

  1. 在配置文件中定义webpack常量,用于接收webpack对象

    commonJS:

    js 复制代码
    const webpack = require('webpack')

    ECMAScript:

    js 复制代码
    import webpack from 'webpack'
  2. 在配置文件中新增plguin插件:

    commonJS:

    js 复制代码
    module.exports = {
    	//......
    	//插件:给webpack提供更多的功能
        plugins: [
            //......
            new webpack.DefinePlugin({
            	'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
            })
        ],
        //......
    }

    ECMAScript:

    js 复制代码
    export default {
    	//......
    	//插件:给webpack提供更多的功能
        plugins: [
            //......
            new webpack.DefinePlugin({
            	'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
            })
        ],
        //......
    }
  3. 在入口文件中设置用来控制console.log的函数。可以把这一部分放在最开头,用来控制所有的cnsole.log。

    js 复制代码
    if (process.env.NODE_ENV === 'production') {
        console.log = function () { }
    }
    console.log('开发模式下显示,生产模式下消失')

开发环境调错

在使用webpack打包代码后,代码会被压缩和混淆,无法正确定位源代码的位置(行数和列数)

source-map功能 可以追你却追踪error和warning在原始代码中的位置

注意:source-map 仅适用于开发环境,一般不在生产模式下使用(防止被轻易查看代码位置)

步骤:

  1. 在配置文件中设置devtool功能。

    js 复制代码
    export default {
      // ......
      devtool: 'inline-source-map', 
      // ......
    };

    但是我们希望在开发环境下增添此功能,在生产模式下不用此功能。

    我们将总体配置模块(export default{...}或者module.exports = {...}设为变量,通过env功能条件判断来给开发模式加上此功能。生产模式下不设置 devtool 也可以减少打包文件体积并保护源代码。

    commonjs:

    js 复制代码
    const config = {
    	// 把原来的module.exports = {}中的配置内容挪到此处
    }
    if (process.env.NODE_ENV === 'development') {
    	config.devtool = 'inline-source-map'
    }
    module.exports = config

    ECMAScript

    js 复制代码
    const config = {
    	// 把原来的export default{}中的配置内容挪到此处
    }
    if (process.env.NODE_ENV === 'development') {
    	config.devtool = 'inline-source-map'
    }
    export default config;
  2. 可以在不同环境下打包并运行带有错误代码的入口文件并观察控制台中的报错信息。

解析别名 alias

解析别名:创建import引入路径的别名,来确保模块引入变得更简单

一般情况下,路径较长且相对路径不安全例如:

js 复制代码
import {checkPhone, checkCode} from '../src/utils/check.js'

我们可以在配置文件中配置解析别名'@'来代表src绝对路径。

步骤:

  1. 在配置文件中配置resolve.alias选项

    js 复制代码
    const config = {
    	// ...... 
    
        // 解析
        resolve: {
            // 别名
            alias: {
                //也可以起别的名字
                '@': path.resolve(__dirname, 'src')
            }
        }
    }
  2. 在入口文件中进行使用:

    js 复制代码
    import youAxios from '@/utils/request.js'
    console.log(youAxios)
  3. 打包并观察:

    bash 复制代码
    npm run dev

    控制台信息:

    txt 复制代码
    index.js:119 
    ƒ wrap() {
        return fn.apply(thisArg, arguments);
      }

优化-CDN技术(可选)

CDN:内容分发网络,指的是一组分布在各个地区的服务器

作用:把静态资源文件 / 第三方库放在CDN网络中各个服务器中,供用户就近请求获取

好处:减轻自己服务器请求压力,就近请求物理延迟低,配套缓存策略

需求:开发模式使用本地第三方库,生产模式下使用CDN加载引入

步骤:

  1. 在html中引入第三方库CDN地址并用模版语法判断
  2. 在配置文件中设置 externals :外部扩展选项(防止某些import的包被打包)
  3. 在两种模式下分别打包观察效果
html 复制代码
<!--在html中插入js代码 -->
<% ...js代码.... () { %>
	<....html....>
<% } %>
html 复制代码
<script defer="defer" src="#"></script>

多页面打包

单页面:单html文件,切换DOM的方式实现不同业务逻辑展示(vue / React)

多页面:多个html文件,切换页面实现不同的业务逻辑展示

需求:把三个页面一起引入打包使用

步骤:

  1. 准备源码(html js css)放入相应位置,并改用模块化语法导出

  2. 下载 form-serialize 包并带入到核心代码中使用(可选)

  3. 在配置文件中配置多入口和多界面的设置

    js 复制代码
    const config = {
        // 配置开发环境:设置打包模式为开发模式
        // mode: 'development',
    
        // 入口文件和出口文件 
        // 单页面入口
        // entry: path.resolve(__dirname, 'src/login/index.js'),
    
        // 多页面入口
        'entry': {
            'login': path.resolve(__dirname, 'src/login/index.js'),
            'content': path.resolve(__dirname, 'src/content/index.js')
        },
    
        output: {
            // 只能导出一次对象
            // 设置打包文件所存放的文件夹
            path: path.resolve(__dirname, 'dist'),
            // 设置打包文件的文件名
            // 单页面出口
            // filename: './login/index.js',
            // 多页面出口
            filename: './[name]/index.js',
            clean: true // 生成新的打包内容之前先清空输出目录
        },
    
    
    
        //插件:给webpack提供更多的功能
        plugins: [
            new HtmlWebpackPlugin({
                title: 'ljl', // 可去掉
                template: path.resolve(__dirname, 'public/login.html'),  //模版文件
                // 这里不能用占位符,所以得写两次
                filename: path.resolve(__dirname, 'dist/login/index.html'), //输出文件
                chunks: ['login'] // 引入哪些打包后的模块(和 entry 的 key 一致)
            }),
            new HtmlWebpackPlugin({
                title: 'ljl', // 可去掉
                template: path.resolve(__dirname, 'public/content.html'),  //模版文件
                filename: path.resolve(__dirname, 'dist/content/index.html'),//输出文件
                chunks: ['content']
            }),
            new MiniCssExtractPlugin({
                filename: './[name]/index.css'
            }),  // 生成css文件
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
            })
        ],
    
        // ......
    
    }
  4. 重新打包观察效果

有些没有导出和导入的文件只是为了让目标js代码被一起打包进来,参与html最后的运行

js 复制代码
import '@/utils/auth.js'

import axios from '@/utils/request.js'

import './index.css'

小案例:发布文章界面打包

需求:把发布文章界面一起打包

这里需要下载form-serialize

bash 复制代码
npm i form-serialize
bash 复制代码
npm i @wangeditor/editor

步骤:

  1. 准备发布文章页面源代码,改成模块化的导入和导出方式;
  2. 修改配置,增加一个出口和一个入口;
  3. 打包并观察效果
js 复制代码
import path, { resolve } from 'path';
import { fileURLToPath } from 'url';
// 引入plugins对象
import HtmlWebpackPlugin from 'html-webpack-plugin';
// 提取css代码
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
// 压缩全部css代码
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'

import webpack from 'webpack'

// 在 ESM 里模拟 __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);



const config = {
    // 配置开发环境:设置打包模式为开发模式
    // mode: 'development',

    // 入口文件和出口文件 
    // 单页面入口
    // entry: path.resolve(__dirname, 'src/login/index.js'),

    // 多页面入口
    'entry': {
        'login': path.resolve(__dirname, 'src/login/index.js'),
        'content': path.resolve(__dirname, 'src/content/index.js'),
        'publish': path.resolve(__dirname, 'src/publish/index.js')
    },

    output: {
        // 只能导出一次对象
        // 设置打包文件所存放的文件夹
        path: path.resolve(__dirname, 'dist'),
        // 设置打包文件的文件名
        // 单页面出口
        // filename: './login/index.js',
        // 多页面出口
        filename: './[name]/index.js',
        clean: true // 生成新的打包内容之前先清空输出目录
    },

    // // 配置开发环境:
    //     devServer: {
    //         static: path.resolve(__dirname, 'dist'),
    //         open: true,
    //         port: 8080,
    //         hot: true
    //     },


    //插件:给webpack提供更多的功能
    plugins: [
        new HtmlWebpackPlugin({
            title: 'ljl', // 可去掉
            template: path.resolve(__dirname, 'public/login.html'),  //模版文件
            // 这里不能用占位符,所以得写两次
            filename: path.resolve(__dirname, 'dist/login/index.html'), //输出文件
            chunks: ['login'] // 引入哪些打包后的模块(和 entry 的 key 一致)
        }),
        new HtmlWebpackPlugin({
            title: 'ljl', // 可去掉
            template: path.resolve(__dirname, 'public/content.html'),  //模版文件
            filename: path.resolve(__dirname, 'dist/content/index.html'),//输出文件
            chunks: ['content']
        }),
        new HtmlWebpackPlugin({
            title: 'ljl', // 可去掉
            template: path.resolve(__dirname, 'public/publish.html'),  //模版文件
            filename: path.resolve(__dirname, 'dist/publish/index.html'),//输出文件
            chunks: ['publish']
        }),
        new MiniCssExtractPlugin({
            filename: './[name]/index.css'
        }),  // 生成css文件
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
        })
    ],

    // 加载器:让webpack识别更多模块文件的内容
    module: {
        rules: [
            // css规则
            {
                test: /\.css$/i,
                // use: ['style-loader', 'css-loader'],
                use: [process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader'],
            },

            // less规则
            {
                test: /\.less$/i,
                use: [
                    // compiles Less to CSS
                    // 'style-loader',   不能和minicssextractplugin混用
                    process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader',
                ],
            },

            // 图片资源规则
            {
                test: /\.(png|jpg|jpeg|gif)$/i,
                type: 'asset',
                generator: {
                    filename: 'assets/[hash][ext][query]'
                }
            },
        ],
    },

    // css优化
    optimization: {
        // 最小化
        minimizer: [
            // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释,即同样压缩js代码
            `...`,
            new CssMinimizerPlugin(),
        ],
    },

    // 解析
    resolve: {
        // 别名
        alias: {
            '@': path.resolve(__dirname, 'src')
        }
    }
}

if (process.env.NODE_ENV === 'development') {
    config.devtool = 'inline-source-map'
}
export default config;

优化-分割公共代码

需求:把2个以上的公共代码提取出来

步骤:

  1. 在配置文件中配置 splitChunks 分割功能

    js 复制代码
    // ...
    const config = {
      // ...
      optimization: {
        // ...
        splitChunks: {
          chunks: 'all', // 所有模块动态非动态移入的都分割分析
          cacheGroups: { // 分隔组
            commons: { // 抽取公共模块
              minSize: 0, // 抽取的chunk最小大小字节
              minChunks: 2, // 最小引用数
              reuseExistingChunk: true, // 当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用
              name(module, chunks, cacheGroupKey) { // 分离出模块文件名
                const allChunksNames = chunks.map((item) => item.name).join('~') // 模块名1~模块名2
                return `./js/${allChunksNames}` // 输出到 dist 目录下位置
              }
            }
          }
        }
  2. 打包并观察效果

主目录下会出现一个名为js的文件夹,封装了publish等各个板块的公共代码。

学习方向

  • 页面布局:html + css
  • 逻辑处理:JavaScript
  • 响应请求:AJAX
  • 后端交互:node.js
  • 代码打包优化:webpack
  • 项目实战语言:TypeScript
  • 框架搭建:VUE React
相关推荐
网络点点滴1 小时前
Vue3路由的props
前端·javascript·vue.js
last demo1 小时前
grep和sed
linux·运维·前端·chrome
-曾牛1 小时前
深入解析 XSS 漏洞:原理、分类与攻防实战
前端·安全·web安全·网络安全·渗透测试·xss·原理解析
JK凯1 小时前
前端调试技巧
前端·visual studio code·前端工程化
开源之眼1 小时前
github star 基础IO 文件在内核中是怎么被管理的 重定向的含义 在自定义shell中加入重定向
前端
JZXStudio1 小时前
独立开发者亲测:MLX框架让我的App秒变AI原生!15年iOS老兵的2025新感悟
前端·ios
cindershade1 小时前
Vue 3:我在真实项目中如何用事件委托
前端
我叫黑大帅1 小时前
存储管理在开发中有哪些应用?
前端·后端·全栈
鲨叔1 小时前
zustand 从原理到实践 - 原理篇(2)
前端·react.js