MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Webpack与Vue框架的项目搭建与优化技巧

2022-09-257.8k 阅读

Webpack 基础介绍

Webpack 是一款现代 JavaScript 应用程序的静态模块打包工具。在 Web 开发中,随着项目规模的增大,会有大量的 JavaScript、CSS、图片等各种资源文件。Webpack 可以将这些资源文件视为一个个模块,通过特定的规则和插件,将它们打包成适合在浏览器中运行的静态资源。

Webpack 的核心概念包括入口(entry)、输出(output)、加载器(loader)和插件(plugin)。

  • 入口(entry):指定 Webpack 从哪个文件开始打包,这个文件就像是项目的起点,Webpack 会从这个入口文件开始,根据模块之间的依赖关系,递归地构建出整个应用程序的依赖图。例如,在一个简单的 Vue 项目中,入口文件可能是 src/main.js
// webpack.config.js
module.exports = {
    entry: './src/main.js'
};
  • 输出(output):定义 Webpack 打包后的文件输出到哪里,以及输出文件的名称等。通常会指定一个输出目录和文件名。
// webpack.config.js
module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    }
};

这里使用 path.resolve(__dirname, 'dist') 来指定输出目录为项目根目录下的 dist 文件夹,filename 指定输出文件名为 bundle.js

  • 加载器(loader):Webpack 本身只能理解 JavaScript 和 JSON 文件,对于其他类型的文件,如 CSS、图片、Vue 单文件组件等,就需要使用加载器(loader)来将这些文件转换为 Webpack 能够处理的模块。例如,css-loader 用于处理 CSS 文件,vue - loader 用于处理 Vue 单文件组件。以处理 CSS 文件为例,需要安装 css-loaderstyle-loadercss-loader 负责解析 CSS 文件中的 @importurl() 等导入语句,style-loader 则将 CSS 插入到 DOM 中。
// webpack.config.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                   'style-loader',
                    'css-loader'
                ]
            }
        ]
    }
};

这里 test 字段用于匹配文件扩展名,use 数组中指定了处理 CSS 文件要使用的加载器,加载器的执行顺序是从右到左(从下到上)。

  • 插件(plugin):插件用于在 Webpack 打包的不同阶段执行一些额外的操作,比如清理输出目录、压缩代码、生成 HTML 文件等。html - webpack - plugin 是一个常用的插件,它可以自动生成一个 HTML 文件,并将打包后的 JavaScript 文件插入到这个 HTML 文件中。
// webpack.config.js
const HtmlWebpackPlugin = require('html - webpack - plugin');

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

这里通过 new HtmlWebpackPlugin() 创建一个插件实例,并指定 template 为项目源文件中的 index.html,这样就会根据这个模板生成最终的 HTML 文件。

Vue 框架与 Webpack 的结合

Vue 是一款流行的 JavaScript 前端框架,它采用组件化的开发模式,使得代码的可维护性和复用性大大提高。在 Vue 项目中使用 Webpack 可以更好地管理项目的各种资源和构建过程。

创建 Vue 项目

可以使用 Vue CLI 快速创建一个基于 Webpack 的 Vue 项目。首先确保全局安装了 Vue CLI:

npm install -g @vue/cli

然后使用以下命令创建项目:

vue create my - vue - project

在创建过程中,可以选择一些预设配置,如是否使用 ESLint 进行代码检查、是否使用路由等。Vue CLI 内部集成了 Webpack,并根据选择的配置生成相应的 Webpack 配置文件。

目录结构分析

以 Vue CLI 创建的项目为例,其目录结构如下:

my - vue - project
├── babel.config.js
├── dist
├── node_modules
├── package - lock.json
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   ├── main.js
│   ├── App.vue
│   └── router
│       └── index.js
├── tests
│   └── unit
│       ├── HelloWorld.spec.js
│       └── jest.config.js
├── vue.config.js
  • public 目录:存放静态资源,如 index.html 是项目的入口 HTML 文件,favicon.ico 是网站的图标。
  • src 目录:是项目的源代码目录,main.js 是项目的入口 JavaScript 文件,在这里会引入 Vue 实例并挂载到 DOM 元素上。App.vue 是项目的根组件,其他组件通常存放在 components 目录下,router 目录用于存放路由相关的配置文件。
  • package.json:记录项目的依赖包和一些脚本命令等信息。
  • vue.config.js:这是 Vue CLI 项目的配置文件,可以在这里对 Webpack 进行一些自定义配置。

配置 Webpack 支持 Vue 单文件组件

Vue 单文件组件以 .vue 为扩展名,包含了模板(template)、脚本(script)和样式(style)三部分。要让 Webpack 支持处理 Vue 单文件组件,需要安装 vue - loadervue - template - compiler

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

然后在 webpack.config.js 中配置 vue - loader

const VueLoaderPlugin = require('vue - loader/lib/plugin');

module.exports = {
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue - loader'
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin()
    ]
};

这里通过 new VueLoaderPlugin() 来启用 vue - loader 的功能。vue - loader 会将 Vue 单文件组件中的模板、脚本和样式分别进行处理,模板部分会被编译成渲染函数,样式部分会根据配置使用相应的 CSS 加载器进行处理。

项目搭建中的优化技巧

代码拆分

随着项目的不断增大,打包后的文件体积也会越来越大,这会导致页面加载时间变长。代码拆分可以将代码分割成多个较小的文件,在需要的时候再加载。Webpack 提供了多种代码拆分的方式,其中一种常用的是使用 splitChunks 插件。

webpack.config.js 中配置 splitChunks

module.exports = {
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    }
};

chunks: 'all' 表示对所有类型的 chunks(入口 chunk 和异步 chunk)都进行代码拆分。Webpack 会自动将一些公共的模块提取出来,生成单独的文件。例如,多个页面都依赖的 Vue 库,就会被提取到一个单独的文件中,这样在多个页面加载时,只需要加载一次这个公共文件,提高了加载效率。

还可以通过一些更细致的配置来控制代码拆分的规则。比如,将所有的第三方库(如 Vue、axios 等)拆分到一个文件中:

module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name:'vendors',
                    chunks: 'all'
                }
            }
        }
    }
};

这里 cacheGroups 定义了缓存组,vendor 缓存组通过 test 匹配 node_modules 中的模块,name 指定拆分后的文件名,chunks: 'all' 表示对所有类型的 chunks 都应用这个规则。

压缩代码

压缩代码可以减少文件体积,提高加载速度。Webpack 可以通过 terser - webpack - plugin 对 JavaScript 代码进行压缩,通过 css - minimizer - webpack - plugin 对 CSS 代码进行压缩。

安装插件:

npm install terser - webpack - plugin css - minimizer - webpack - plugin --save - dev

webpack.config.js 中配置:

const TerserPlugin = require('terser - webpack - plugin');
const CssMinimizerPlugin = require('css - minimizer - webpack - plugin');

module.exports = {
    optimization: {
        minimizer: [
            new TerserPlugin(),
            new CssMinimizerPlugin()
        ]
    }
};

TerserPlugin 会默认使用 Terser 对 JavaScript 代码进行压缩,移除未使用的代码、缩短变量名等操作。CssMinimizerPlugin 会对 CSS 代码进行压缩,如移除多余的空格、合并重复的样式等。

优化图片加载

在前端项目中,图片通常会占用较大的体积。可以通过以下几种方式优化图片加载。

  • 使用图片压缩工具:在构建过程中,可以使用 image - webpack - loader 对图片进行压缩。安装:
npm install image - webpack - loader --save - dev

webpack.config.js 中配置:

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'file - loader',
                        options: {
                            name: 'images/[name].[ext]'
                        }
                    },
                    {
                        loader: 'image - webpack - loader',
                        options: {
                            mozjpeg: {
                                progressive: true,
                                quality: 65
                            },
                            // optipng.enabled: false will disable optipng
                            optipng: {
                                enabled: false
                            },
                            pngquant: {
                                quality: [0.65, 0.90],
                                speed: 4
                            },
                            gifsicle: {
                                interlaced: false
                            },
                            // the webp option will enable WEBP
                            webp: {
                                quality: 75
                            }
                        }
                    }
                ]
            }
        ]
    }
};

image - webpack - loader 支持多种图片格式的压缩,如 JPEG、PNG、GIF 等,可以通过 options 配置压缩的参数,如 mozjpeg 用于配置 JPEG 图片的压缩质量,pngquant 用于配置 PNG 图片的压缩质量和速度等。

  • 使用响应式图片:可以通过 HTML 的 srcsetsizes 属性来实现响应式图片加载。在 Vue 项目中,可以在模板中这样使用:
<template>
    <img
        :srcset="`small.jpg 100w, medium.jpg 200w, large.jpg 300w`"
        :sizes="`(max - width: 600px) 100vw, 600px`"
        src="medium.jpg"
        alt="Responsive Image"
    />
</template>

srcset 中指定了不同分辨率的图片路径和对应的宽度描述,sizes 中定义了不同屏幕宽度下图片的显示宽度。浏览器会根据设备的屏幕宽度和像素密度自动选择最合适的图片进行加载,避免加载过大的图片。

优化 CSS 加载

  • 使用 CSS 提取插件:在 Vue 项目中,默认情况下,CSS 会被打包到 JavaScript 文件中。这样会导致 JavaScript 文件体积增大,影响加载速度。可以使用 mini - css - extract - plugin 将 CSS 提取到单独的文件中。 安装:
npm install mini - css - extract - plugin --save - dev

webpack.config.js 中配置:

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

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css - loader']
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin()
    ]
};

MiniCssExtractPlugin.loader 会将 CSS 从 JavaScript 中提取出来,MiniCssExtractPlugin 插件会生成单独的 CSS 文件。这样在页面加载时,CSS 文件可以并行加载,提高加载效率。

  • 优化 CSS 顺序:在 Webpack 配置中,CSS 加载器的顺序会影响最终的 CSS 效果。一般来说,应该先加载处理 CSS 导入和解析的 css - loader,再加载将 CSS 插入到 DOM 中的 style - loader(如果不使用 mini - css - extract - plugin)。如果顺序错误,可能会导致 CSS 样式不生效或出现奇怪的显示问题。

性能监控与分析

使用 Webpack Bundle Analyzer

webpack - bundle - analyzer 是一个非常有用的工具,它可以生成一个可视化的图表,展示打包后的文件中各个模块的大小和依赖关系。这有助于我们发现哪些模块体积过大,从而进行针对性的优化。

安装:

npm install webpack - bundle - analyzer --save - dev

webpack.config.js 中配置:

const BundleAnalyzerPlugin = require('webpack - bundle - analyzer').BundleAnalyzerPlugin;

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

运行 Webpack 打包后,会自动打开一个浏览器窗口,显示打包文件的分析图表。在图表中,可以看到各个模块的大小,通过点击模块还可以查看其依赖关系。例如,如果发现某个第三方库体积过大,可以考虑是否可以使用更小的替代品,或者只引入该库中实际需要的部分。

Lighthouse 性能审计

Lighthouse 是 Chrome 浏览器提供的一个开源的自动化工具,用于对网页进行性能、可访问性、最佳实践等方面的审计。在 Vue 项目中,可以在 Chrome 浏览器中打开项目页面,然后按下 Ctrl + Shift + I(Windows/Linux)或 Command + Option + I(Mac)打开开发者工具,切换到 Lighthouse 标签页,点击 Generate report 按钮,Lighthouse 会对页面进行分析,并生成详细的报告。

报告中会给出性能得分以及具体的优化建议,例如图片未压缩、JavaScript 加载时间过长等问题。根据这些建议,可以进一步优化项目,提高页面的性能。比如,如果报告指出某个图片过大,就可以使用前面提到的图片压缩方法进行优化;如果 JavaScript 加载时间过长,可以检查代码拆分和压缩的配置是否合理。

生产环境与开发环境的配置区分

在实际开发中,生产环境和开发环境的 Webpack 配置通常是不同的。开发环境更注重开发体验,如快速的编译速度、友好的错误提示等;而生产环境更注重性能和稳定性。

开发环境配置

在开发环境中,通常会使用 webpack - dev - server 来提供一个开发服务器,实现热模块替换(HMR)功能,使得在代码修改后,页面能够实时更新,而不需要刷新整个页面。

安装:

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

webpack.config.js 中配置:

module.exports = {
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        compress: true,
        port: 3000,
        hot: true
    }
};

contentBase 指定开发服务器的根目录,compress 开启 gzip 压缩,port 指定服务器端口,hot 开启热模块替换功能。这样在开发过程中,修改代码后,相关的模块会被热替换,大大提高了开发效率。

同时,在开发环境中,可以关闭一些生产环境中才需要的优化插件,如代码压缩插件,因为这些插件会增加编译时间,影响开发体验。

生产环境配置

在生产环境中,主要目标是优化性能,如前面提到的代码拆分、压缩代码、优化图片和 CSS 加载等操作都应该开启。同时,还可以对输出的文件进行命名优化,比如在文件名中添加哈希值,这样可以更好地实现浏览器缓存。

webpack.config.js 中配置输出文件名包含哈希值:

module.exports = {
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.[contenthash].js'
    }
};

[contenthash] 会根据文件的内容生成一个哈希值,当文件内容发生变化时,哈希值也会改变。这样在部署新版本时,如果文件内容没有变化,浏览器可以直接从缓存中加载,提高加载速度。

另外,在生产环境中,应该开启更严格的代码检查和错误处理机制,确保项目的稳定性。例如,可以配置 ESLint 对代码进行严格的语法检查,并且在 Webpack 配置中设置 mode: 'production',Webpack 在生产模式下会启用一些默认的优化,如压缩代码、移除未使用的代码等。

module.exports = {
    mode: 'production'
};

多页应用的项目搭建与优化

多页应用的特点

多页应用(MPA)是指一个应用由多个页面组成,每个页面都有自己独立的 HTML、JavaScript 和 CSS 文件。与单页应用(SPA)不同,MPA 的页面跳转通常会触发浏览器的页面刷新。在一些大型项目中,多页应用可以更好地进行模块划分和管理,每个页面可以独立开发和维护。

多页应用的 Webpack 配置

在 Webpack 中搭建多页应用,需要配置多个入口和输出。假设项目有两个页面,分别是 indexabout,目录结构如下:

src
├── pages
│   ├── index
│   │   ├── index.js
│   │   └── index.html
│   └── about
│       ├── about.js
│       └── about.html
└── common
    └── common.js

webpack.config.js 中配置:

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

function getEntry() {
    const entry = {};
    const pages = ['index', 'about'];
    pages.forEach(page => {
        entry[page] = `./src/pages/${page}/${page}.js`;
    });
    return entry;
}

function getHtmlPlugins() {
    const htmlPlugins = [];
    const pages = ['index', 'about'];
    pages.forEach(page => {
        htmlPlugins.push(
            new HtmlWebpackPlugin({
                template: `./src/pages/${page}/${page}.html`,
                filename: `${page}.html`,
                chunks: [page, 'common']
            })
        );
    });
    return htmlPlugins;
}

module.exports = {
    entry: getEntry(),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[chunkhash].js'
    },
    module: {
        rules: [
            // 其他规则
        ]
    },
    plugins: [
       ...getHtmlPlugins()
    ]
};

这里通过 getEntry 函数动态生成多个入口,getHtmlPlugins 函数生成多个 HtmlWebpackPlugin 实例,每个实例对应一个页面的 HTML 文件生成和相关的 JavaScript 插入。chunks 数组指定了每个 HTML 文件需要引入的 JavaScript chunks,其中 common 是公共模块,这样可以将公共代码提取出来,避免重复加载。

多页应用的优化技巧

  • 公共代码提取:对于多页应用中的公共代码,如一些通用的库、样式等,应该提取出来,避免每个页面都重复加载。可以通过 splitChunks 插件来实现公共代码的提取,配置如下:
module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                common: {
                    name: 'common',
                    chunks: 'initial',
                    minChunks: 2
                }
            }
        }
    }
};

这里 cacheGroups.common 表示公共模块的缓存组,name 指定公共模块的文件名,chunks: 'initial' 表示对入口 chunk 进行拆分,minChunks: 2 表示至少有两个入口 chunk 依赖的模块才会被提取到公共模块中。

  • 懒加载:对于一些不常用的页面或模块,可以采用懒加载的方式,在需要的时候再加载。在多页应用中,可以通过动态导入的方式实现懒加载。例如,在 index.js 中:
document.getElementById('about - link').addEventListener('click', () => {
    import('./about/about.js').then(module => {
        // 在这里执行 about 页面的相关逻辑
    });
});

这样当用户点击 about - link 时,才会加载 about.js 文件,提高了页面的初始加载速度。

  • 预渲染:对于一些静态页面,可以使用预渲染技术,在构建过程中生成 HTML 文件,这样在页面加载时,浏览器可以直接显示预渲染好的内容,提高用户体验。可以使用 prerender - spa - plugin 等工具来实现多页应用的预渲染。安装:
npm install prerender - spa - plugin --save - dev

webpack.config.js 中配置:

const PrerenderSPAPlugin = require('prerender - spa - plugin');
const path = require('path');

module.exports = {
    plugins: [
        new PrerenderSPAPlugin({
            staticDir: path.join(__dirname, 'dist'),
            routes: ['/', '/about']
        })
    ]
};

这里 staticDir 指定输出目录,routes 定义需要预渲染的页面路径。预渲染后的 HTML 文件会保存在指定的输出目录中。

与 CI/CD 的集成

持续集成(CI)

持续集成是指开发团队成员频繁地将代码合并到共享的仓库中,每次合并都会触发自动化的构建、测试等流程。在 Vue 项目中,可以使用 Jenkins、GitLab CI/CD 等工具实现持续集成。

以 GitLab CI/CD 为例,在项目根目录下创建 .gitlab-ci.yml 文件,内容如下:

image: node:latest

stages:
  - build

build:
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    when: always
    paths:
      - dist

这里 image 指定使用最新的 Node.js 镜像,stages 定义了构建阶段,build 部分定义了具体的构建脚本。首先安装项目依赖,然后执行 npm run build 进行项目构建。artifacts 部分表示将构建后的 dist 目录作为产物保存下来,以便后续的部署使用。

持续交付(CD)

持续交付是在持续集成的基础上,将构建好的产物自动部署到生产环境或其他测试环境。同样以 GitLab CI/CD 为例,可以在 .gitlab-ci.yml 文件中添加部署阶段:

image: node:latest

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    when: always
    paths:
      - dist

deploy:
  stage: deploy
  script:
    - echo "Deploying to production..."
    - # 这里添加实际的部署脚本,如使用 SSH 上传到服务器等
  only:
    - master

deploy 阶段定义了部署脚本,only: master 表示只有在 master 分支有代码推送时才触发部署。实际的部署脚本可能包括使用 SSH 连接到服务器,将 dist 目录下的文件上传并部署到相应的位置。通过持续集成和持续交付的集成,可以实现代码从开发到生产环境的快速、自动化流转,提高项目的开发效率和质量。

通过以上对 Webpack 与 Vue 框架项目搭建与优化技巧的介绍,希望能帮助开发者更好地构建高效、稳定的前端项目,提升用户体验。无论是单页应用还是多页应用,通过合理的配置和优化,都能在性能方面得到显著提升。同时,与 CI/CD 的集成也能进一步提高项目的开发和部署效率。