likes
comments
collection
share

从零开始实现 webpack + Vue全家桶项目框架(2)

作者站长头像
站长
· 阅读数 1

本文将带你从零开始,逐步搭建一个基于 webpack 和 Vue 全家桶(包括 Vue.js 本身、Vue Router、Vuex 等)的项目框架。我们不仅会深入探讨 webpack 的配置和 Vue 组件的开发,还会涉及到如何集成 Vue Router 实现路由管理,以及如何利用 Vuex 进行状态管理。

通过本文的学习,你将能够掌握从零开始搭建 webpack + Vue 全家桶项目框架的技能,为你的前端开发之路增添一份强大的武器。无论你是前端新手还是有一定经验的开发者,相信本文都能为你带来不小的收获。

接下来,让我们正式开启这次探索之旅吧!

上一篇文章我们实现了基本的打包工具,这篇文章我们来进行一些优化。

配置实现代码分离

代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后便能按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle、控制资源加载优先级,如果使用合理,会极大减小加载时间。

通过optimization选项,对项目进行一些优化
optimization: {
    //对于动态导入模块,默认使用 webpack v4+ 提供的全新的通用分块策略(common chunk strategy)。
    splitChunks: {
        //这表明将选择哪些 chunk 进行优化。当提供一个字符串,有效值为 all,async 和 initial。
        // 设置为 all 可能特别强大,因为这意味着 chunk 可以在异步和非异步 chunk 之间共享。
        chunks: 'all', // 必须三选一: "initial" | "all" | "async"(默认就是异步)
    },
    runtimeChunk: 'single' // 将包含chunks映射关系的list单独从入口文件里提取出来,方便浏览器缓存,否则会在入口文件js中每次都会发生变化,所有的入口文件一起共同生成一个runtimeChunk。
    // runtimeChunk: { name: "runtimechunk" },//同上,起个别名
    // runtimeChunk: {
    //   name: (entrypoint) => `runtimechunk~${entrypoint.name}`,//每个entry入口文件都生成一个runtimeChunk
    // },
},

从零开始实现 webpack + Vue全家桶项目框架(2)

filename的配置也要改,然后继执行npm run build 我们可以看到dist文件下文件的变化,并且打包后的体积明显缩小

配置提取单独的css文件

本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
利用minicssextractPlugin提出单独的css文件

npm install --save-dev mini-css-extract-plugin

从零开始实现 webpack + Vue全家桶项目框架(2)

#### 利用cssMinimizerWebpackPlugin优化和压缩 CSS

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

从零开始实现 webpack + Vue全家桶项目框架(2)

然后继执行npm run build 我们可以看到dist文件下文件的变化,没有报错,我们继续

配置babel将es6语法解析成es5语法

使用babel将各种js相关的文件解析为浏览器能识别的es5语法

npm install -D babel-loader @babel/core @babel/preset-env webpack

在modelu中的rules下增加配置

{
    test: /.(js|mjs|jsx|ts|tsx)$/,
    exclude: /(node_modules)/,
    // include: path.resolve(__dirname, '../src'),
    use: {
        loader: 'babel-loader'
    }
},

基本的配置和优化有了,下面我们开始加入Vue

在加入vue全家桶(vue3、vue-router、vuex、element-plus)之前,需要让webpack能编绎.vue文件,所以我们需要添加vue-loader来实现

npm install vue vue-router vuex element-plus --save

npm install vue-loader -D

从零开始实现 webpack + Vue全家桶项目框架(2)

从零开始实现 webpack + Vue全家桶项目框架(2)

从零开始实现 webpack + Vue全家桶项目框架(2)

- 修改src/index.js引入vue
import { createApp  } from 'vue';

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

import App from './App.vue'

const app = createApp(App);

app.use(ElementPlus);
app.mount('#app');
添加public文件夹创建index.html模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="./favicon.ico" type="image/x-icon" />
    <title>脚手架学习</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
添加src/App.vue
<template>
    <div>
       vue3
    </div>
</template>

<script>

</script>

<style lang="less"></style>

然后我们执行npm run build 完成后,打开dist中的index.html 看到vue3就成功了

然后我们引入element 试试

最后我们配置开发不必每次都打包看效果

需要用到 热更新 所以我们先安装 webpack-dev-server

npm install -D webpack-dev-server

从零开始实现 webpack + Vue全家桶项目框架(2)

从零开始实现 webpack + Vue全家桶项目框架(2)

然后执行npm run dev

现在基本框架就ok了,但是webpack的当前配置都是基本的配置,还有很多的配置没有写到,后期继续完善

基本配置

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 抽取css插件
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); // css 压缩插件
const {VueLoaderPlugin} = require('vue-loader');

module.exports = {
  mode:'development',
  devtool: 'inline-source-map', // 正式环境也添加source-map,开发环境调试,使用inline-source-map
  entry: './src/index.js',
   devServer: {
        //该配置项允许配置从目录提供静态文件的选项(默认是 'public' 文件夹)。将其设置为 false 以禁用:
        static: {
            directory: path.join(__dirname, '../dist')
        },
        client: {
            progress: true
        },
        compress: true, // 启用 gzip compression:
        historyApiFallback: true,
        hot: true,
        open: true, // 自动打开浏览器
        port: '9527', // 自动使用一个可用端口
        // proxy: {
        //     '/api': {
        //         target: 'http://localhost:3000',
        //     },
        // },
    },
  plugins: [
    new HtmlWebpackPlugin({
      title: '管理输出',
      template: './public/index.html' // 这是html模板存放的地址
    }),
     //本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css' // 所有的css都放在css文件夹下
    }),
      //加载并编译 Vue 组件
    new VueLoaderPlugin()
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
   optimization: {
        minimize: true, // 如果是ture会进行js、css压缩,会产生LICENSE.txt文件,把注释提取到单独的txt文件中
        minimizer: [
            // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
            `...`, // js的压缩全靠这三个...,webpack认为,如果配置了minimizer,就表示开发者在自定义压缩插件,无论配置minimizer是true还是false,内部的JS压缩器都会被覆盖掉。所以我们这里要手动把它加回来,webpack内部使用的JS压缩器是terser-webpack-plugin.
            new CssMinimizerPlugin()
        ],
        //对于动态导入模块,默认使用 webpack v4+ 提供的全新的通用分块策略(common chunk strategy)。
        splitChunks: {
            //这表明将选择哪些 chunk 进行优化。当提供一个字符串,有效值为 all,async 和 initial。
            // 设置为 all 可能特别强大,因为这意味着 chunk 可以在异步和非异步 chunk 之间共享。
            chunks: 'all', // 必须三选一: "initial" | "all" | "async"(默认就是异步)
        },
        runtimeChunk: 'single' // 将包含chunks映射关系的list单独从入口文件里提取出来,方便浏览器缓存,否则会在入口文件js中每次都会发生变化,所有的入口文件一起共同生成一个runtimeChunk。
        // runtimeChunk: { name: "runtimechunk" },//同上,起个别名
        // runtimeChunk: {
        //   name: (entrypoint) => `runtimechunk~${entrypoint.name}`,//每个entry入口文件都生成一个runtimeChunk
        // },
    },
  module: {
        //创建模块时,匹配请求的规则数组。
        // 这些规则能够修改模块的创建方式。
        // 这些规则能够对模块(module)应用 loader,或者修改解析器(parser)。
        rules: [
            {
                test: /\.css$/i,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.less$/i,
                use: ['style-loader', 'css-loader', 'less-loader']
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset/resource'
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/i,
                type: 'asset/resource'
            },
            {
                test: /\.vue$/,
                exclude: /node_modules/,
                use: 'vue-loader'
            },
            {
                test: /\.(js|mjs|jsx|ts|tsx)$/,
                exclude: /(node_modules)/,
                // include: path.resolve(__dirname, '../src'),
                use: {
                    loader: 'babel-loader'
                }
            },
        ]
    }
};