使用 webpack 从0开始搭建 vue3+sass+element-plus+typescript 项目

4 篇文章 0 订阅

从官网下载nodejs

Download | Node.js

下载适合你电脑的对应版本,选择老版本的node可以防止出现兼容问题

安装Node.js

node -v

npm也安装好了

npm -v

 创建文件夹

mkdir project

进入

cd project

npm初始化

npm init

新建public文件夹index.html,新建 src/index.js

<body>
    <div id="app"></div>
</body>

下载 webpack 核心库,webpack 指令库

npm i webpack webpack-cli

新建webpack.config.js文件

webpack只可以解析js,要解析其它文件就要下载加载器

先下载html webpack 插件

npm i html-webpack-plugin

下载开发服务器

npm i webpack-dev-server

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    mode: 'development',//开发模式
    entry: './src/index.js', //入口文件
    devServer: { // 开发服务器
        port: 8080
    },
    plugins: [   //插件
        new HtmlWebpackPlugin({
            template: path.join(__dirname, './public/index.html')
            //以哪个html文件作为模板,这将是 spa
        }),
    ]
}

在package.json配置开发环境命令

  "scripts": {
    "dev": "webpack serve --config ./webpack.config.js"
  },

运行:

npm run dev

打开 localhost:8080 就可以看到项目

接下来使用 vue 文件

下载vue:

npm i vue

src 创建 App.vue

<template>
    <div class="a">{{ msg }}</div>
</template>
<script>
export default {
    name: 'app',
    data() {
        return {
            msg: 'App.vue'
        }
    }
}
</script>

index.js(vue3的写法):

import { createApp } from 'vue';
import App from './App.vue'

const app = createApp(App);
app.mount('#app');

下载 vue-loader

Introduction | Vue Loader

npm i vue-loader

引入:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
    mode: 'development',//开发模式
    entry: './src/index.js', //入口文件
    devServer: { // 开发服务器
        port: 8080
    },
    plugins: [   //插件
        new HtmlWebpackPlugin({
            template: path.join(__dirname, './public/index.html')
            //以哪个html文件作为模板,这将是 spa
        }),
        new VueLoaderPlugin()
    ],
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
        ]
    }
}

加载css、scss文件:

下载:

npm i style-loader css-loader sass sass-loader

配置规则:

webpack.config.js:

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/i,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
        ]
    }
}

注意顺序:sass-loader会将scss代码转化为css代码,css-loader处理之后会导出样式数组,style-loader 是通过一个JS脚本创建一个style标签,里面包含一些样式。

App.vue:

<template>
    <div class="a">{{ msg }}</div>
</template>
<script>
export default {
    name: 'app',
    data() {
        return {
            msg: 'App.vue'
        }
    }
}
</script>
<style scoped>
.a {
    color: red;
    background-color: green;
}
</style>
<style lang="scss">
.a {
    width: 300px;
    height: 300px;
}
</style>

新建 src/style.css:

.a {
    font-size: 40px;
}

src/style.scss:

body {
    #app {
        .a {
            font-weight: bold;
        }
    }
}

index.js:

import './style.css'
import './style.scss'
import { createApp } from 'vue';
import App from './App.vue'

const app = createApp(App);
app.mount('#app');

这样,所有样式都是正常的:

在style标签上加scoped属性,实现样式在当前组件生效:

<style scoped>
.a {
    color: red;
    background-color: green;
}
</style>

经过 vue-loader 处理之后会变成这样:

.a[data-v-7ba5bd90] {
    color: red;
    background-color: green;
}

vue-loader 处理过后就到了 css-loader,之后就到 style-loader

css-loader 处理过后会被 vue-style-loader 引用,方便在 vue 文件中创建 style 标签把样式给到 dom,vue-style-loader 还支持服务端渲染,如果你的 vue 项目是需要支持服务端渲染的,那么就需要 vue-style-loader 了

npm i vue-style-loader

引入:

    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
        ]
    }

使用 axios 发送请求

npm i axios

新建 /src/api/index.js ,配置基础地址、请求超时、请求拦截、响应拦截

使用 element-ui 提供的消息提示,这里是 vue3,使用element-plus

安装 | Element Plus

npm i element-plus

全局注册 element-plus:

import './style.css'
import './style.scss'
import { createApp } from 'vue';
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

const app = createApp(App);
// 中文化
app.use(ElementPlus, {
    locale: zhCn,
})
// 注册 icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
}
app.mount('#app');

/src/api/index.js :

import axios from 'axios'
import { ElMessage } from 'element-plus'

const server = axios.create({
    // 配置一个公共的前置链接
    baseURL: 'http://127.0.0.1:3030',
    // 请求超时
    timeout: 5000
})
// 请求拦截
server.interceptors.request.use((config) => {
    config.headers.Authorization = localStorage.getItem('token') || ''
    return config
}, (error) => {
    return Promise.reject(error)
})
// 响应拦截
server.interceptors.response.use((response) => {
    return response
}, (error) => {
    if (error.response?.config.url === '/authentication') return error.response
    if (error.response?.status === 401) {
        ElMessage.warning('没有权限,请重新登录')
        setTimeout(() => {
            window.location.href = '/login'
        }, 1800)
        return error.response
    }
    if (error.response?.status === 404) {
        ElMessage.warning('没有该接口')
        return error.response
    }
    return Promise.reject(error)
})
export default server

新建 /src/api/users.js

import server from '.'

export const getUserList = () => server({
    url: '/users',
    method: 'get',
});

引入 getUserList :

App.vue:

<script>
import { getUserList } from '@/api/users.js'

export default {
    name: 'app',
    data() {
        return {
            msg: 'App.vue',
            data: ''
        }
    },
    methods: {
        async getData() {
            const res = await getUserList()
            console.log(res)
        }
    }
}
</script>

配置绝对路径:

module.exports = {
    resolve: {
        alias: {
            '@': path.join(__dirname, 'src')
        },
    }
}

当然,需要使用 babel-loader 去处理 js 文件:

npm i babel-loader
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.js$/,
                loader: 'babel-loader'
            },
        ]
    }

配置 devTool 可以更细颗粒的反应开发环境遇到的错误和警告

module.exports = {
    devtool: 'eval-cheap-module-source-map',
    }

可以正常获取到数据

App.vue:

<template>
    <div>
        <div class="a">{{ msg }}</div>
        <div v-for="item in data"><span>{{ item.uname }}</span> | <span>{{ item.nickname }}</span></div>
        <el-button type="success" @click="getData">获取数据</el-button>
    </div>
</template>
<script>
import { getUserList } from '@/api/users.js'

export default {
    name: 'app',
    data() {
        return {
            msg: 'App.vue',
            data: []
        }
    },
    methods: {
        async getData() {
            const res = await getUserList()
            this.data = res.data.data
        }
    }
}
</script>
<style scoped>
.a {
    color: red;
    background-color: green;
}
</style>
<style lang="scss">
.a {
    width: 300px;
    height: 300px;
}
</style>

引入图片,新建 /src/assets 目录,放入logo.png

<img src="@/assets/logo.png" alt="">

处理图片:

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|jpeg|gif|svg)$/i,
                type: 'asset',
            }
        ]
    },
}

使用 postcss-px-to-viewport来实现移动端的适配

安装:

npm i postcss postcss-loader postcss-px-to-viewport 

在项目根目录新建一个 postcss.config.js :

module.exports = {
    plugins: {
        'postcss-px-to-viewport': {
            unitToConvert: 'px',  // 要转换的单位 
            viewportWidth: 750,  // 以什么视图大小作为参照(UI设计稿的实际宽度)
            unitPrecision: 5, // 保留的小数位数
            propList: ['*'], // 指定哪些属性需要转换
            viewportUnit: 'vw', // 转换的单位 目标
            fontViewportUnit: 'vw', // 字体的转换单位
            selectorBlackList: [],  // 哪些选择器不做转换
            minPixelValue: 1, // 最小的转换值(大于等于1才开始转换)
            mediaQuery: false, // 是否支持 媒体查询
            replace: true,
            exclude: [/^node_modules$/], // 判断哪些目录下的的文件不转换
            landscape: false,
            landscapeUnit: 'vw',
            landscapeWidth: 568
        }
    }
}

修改 webpack.config.js :

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader',
                    'postcss-loader',
                ]
            },
            {
                test: /\.s[ca]ss$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader',
                    'postcss-loader',
                    'sass-loader'
                ]
            },
        ]
    },
}

经过以上的操作之后,我们写出的页面使用的是px单位,但是,插件会帮我们自动的转换成vw单位。从而能实现移动端的适配。如果是移动端的开发就需要使用这个配置。

配置 typescript 环境

安装 ts-loader:

https://github.com/TypeStrong/ts-loader

npm i ts-loader typescript

引入:

    module: {
        rules: [
            {
                test: /\.(ts|tsx)$/,
                loader: "ts-loader",
            },
        ]
    },

当然,在 vue 文件中 也是ts

<script lang="ts">

</script>
    module: {
        rules: [
            {
                test: /\.(ts|tsx)$/,
                loader: "ts-loader",
                options: { appendTsSuffixTo: [/\.vue$/] }
            },
        ]
    },
module.exports = {
    resolve: {
        // 添加“.ts”和“.tsx”作为可解析的扩展名
        extensions: [".ts", ".tsx", ".js"],
        // 添加对TypeScripts完全限定ESM导入的支持
        extensionAlias: {
            ".js": [".js", ".ts"],
            ".cjs": [".cjs", ".cts"],
            ".mjs": [".mjs", ".mts"]
        },
    }
}

将所有 js 文件改为 ts 文件

/src/api/index.ts :

import axios, { AxiosRequestConfig, AxiosError, AxiosResponse } from 'axios'
import { ElMessage } from 'element-plus'

const server = axios.create({
    // 配置一个公共的前置链接
    baseURL: 'http://127.0.0.1:3030',
    // 请求超时
    timeout: 5000
})
// 请求拦截
server.interceptors.request.use((config: AxiosRequestConfig | any) => {
    config.headers.Authorization = localStorage.getItem('token') || ''
    return config
}, (error: AxiosError) => {
    return Promise.reject(error)
})
// 响应拦截
server.interceptors.response.use((response: AxiosResponse) => {
    return response
}, (error: AxiosError) => {
    if (error.response?.config.url === '/authentication') return error.response
    if (error.response?.status === 401) {
        ElMessage.warning('没有权限,请重新登录')
        setTimeout(() => {
            window.location.href = '/login'
        }, 1800)
        return error.response
    }
    if (error.response?.status === 404) {
        ElMessage.warning('没有该接口')
        return error.response
    }
    return Promise.reject(error)
})
export default server

在根目录新建 tsconfig.json 文件:

{
    "compilerOptions": {
        "sourceMap": true,
        "paths": {
            "@/*": [
                "./src/*"
            ]
        },
        "declaration": true,
    },
}

安装 tsconfig-paths-webpack-plugin 插件解析 tsconfig.json:

tsconfig-paths-webpack-plugin - npm

npm i tsconfig-paths-webpack-plugin

修改 webpack.config.ts :

import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'
module.exports = {
    resolve: {
        plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })],
    }
}

在 ts 环境中 *.vue 文件 sfc 要有 ts 类型校验,要在根目录新建一个 index.d.ts 文件,因为 webpack.config.ts 在根目录而且把 /src/index.ts 作为入口文件,而在 /src/index.ts 中,又以 /src/App.vue 作为 SPA 的根组件

index.d.ts:

// 非 ts 文件都需要声明模块,才可以被导入
declare module '*.vue' {
    import type { DefineComponent } from 'vue';
    const component: DefineComponent<any, any, any>;
    export default component;
}
declare module 'element-plus/dist/locale/zh-cn.mjs'

使用 require 方式导入图片,App.vue:

<template>
    <div>
        <div class="a">{{ msg }}</div>
        <img :src="logo" alt="" class="img">
        <div v-for="item in data"><span>{{ item.uname }}</span> | <span>{{ item.nickname }}</span></div>
        <el-button type="success" @click="getData">获取数据</el-button>
    </div>
</template>
<script lang="ts">
import { getUserList } from '@/api/users'

export default {
    name: 'app',
    data() {
        return {
            logo: require('@/assets/logo.png'),
            msg: 'App.vue',
            data: []
        }
    },
    methods: {
        async getData() {
            const res = await getUserList()
            this.data = res.data.data
        }
    }
}
</script>
<style scoped lang="scss">
.a {
    width: 300px;
    height: 300px;
    color: red;
    background-color: green;
}

.img {
    // background-image: url('@/assets/logo.png');
    width: 200px;
    height: 200px;
}
</style>

使用 vue-router 配置路由:

安装 | Vue Router

npm i vue-router

vue-router 通常使用这两种模式:
hash 模式,使用 URL 中的 # 作为路由,支持所有的浏览器。hash+pushState/hashChange 兼容性好,不刷新页面,因为服务端无法获取hash值,对 seo 优化不好,比如https://baidu.com/a 会直接显示未找到,而 https://baidu.com/#a 还是显示的是百度的首页,因为服务器获取不到# 后面的数据。
history 模式,浏览器提供 historyApi( go/back/forward ) 和新增的两个 pushState()/replaceState (),这两个api可以在不刷新的情况下读取浏览器的历史记录,history模式美观,但是需要服务端的支持,否则刷新会出现404状态。

新建 /src/router/index.ts,使用 histroy 模式,路由懒加载:

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'

const routes: Array<RouteRecordRaw> = [
    {
        path: '/',
        name: '/',
        redirect: '/home'
    },
    {
        path: '/home',
        name: 'home',
        component: import('@/views/Home.vue')
    },
    {
        path: '/about',
        name: 'about',
        component: import('@/views/About.vue')
    },
    {
        path: '/:pathMatch(.*)',
        name: 'notFound',
        component: import('@/views/NotFound.vue')
    }
]
const router = createRouter({
    // createWebHashHistory 带#,兼容IE
    history: createWebHistory(), //不带#
    routes
})
export default router

新建 /src/views/Home.vue、 /src/views/About.vue、 /src/views/NotFound.vue

全局使用 router :
index.ts:

import './style.css'
import './style.scss'
import { createApp } from 'vue';
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

const app = createApp(App);
app.use(router)
// 中文化
app.use(ElementPlus, {
    locale: zhCn,
})
// 注册 icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
}
app.mount('#app');

当使用 history 模式时,URL 会看起来很 "正常"。不过,问题来了,由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 http://localhost:8080/about 就会得到一个 404 错误,这就尴尬了。

不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。

对于原生 Node.js 服务器:

const http = require('http')
const fs = require('fs')
const httpPort = 3030
http.createServer((req, res) => {
    fs.readFile('index.html', 'utf-8', (err, content) => {
        if (err) {
            console.log('We cannot open "index.html" file.')
        }
        res.writeHead(200, {
            'Content-Type': 'text/html; charset=utf-8',
        })
        res.end(content)
    })
}).listen(httpPort, () => {
    console.log('Server listening on: http://localhost:%s', httpPort)
})

配置好了之后,刷新不会出现404状态

App.vue:

<template>
    <div>
        <div>
            <router-link :to="{ name: 'home' }">首页</router-link> |
            <router-link :to="{ name: 'about' }">关于我们</router-link>
        </div>
        <router-view></router-view>
    </div>
</template>
<script lang="ts">

export default {
    name: 'app',
    data() {
        return {
        }
    }
}
</script>

引入 element-plus 的组件:
Table 表格 | Element Plus

/src/views/Home.vue :

<template>
    <el-table ref="singleTableRef" :data="tableData" highlight-current-row style="width: 100%"
        @current-change="handleCurrentChange">
        <el-table-column type="index" width="50" />
        <el-table-column property="date" label="Date" width="120" />
        <el-table-column property="name" label="Name" width="120" />
        <el-table-column property="address" label="Address" />
    </el-table>
    <div style="margin-top: 20px">
        <el-button @click="setCurrent(tableData[1])">Select second row</el-button>
        <el-button @click="setCurrent()">Clear selection</el-button>
    </div>
</template>
  
<script lang="ts" setup>
import { ref } from 'vue'
import { ElTable } from 'element-plus'

interface User {
    date: string
    name: string
    address: string
}
const currentRow = ref()
const singleTableRef = ref<InstanceType<typeof ElTable>>()
const setCurrent = (row?: User) => {
    singleTableRef.value!.setCurrentRow(row)
}
const handleCurrentChange = (val: User | undefined) => {
    currentRow.value = val
}
const tableData: User[] = [
    {
        date: '2016-05-03',
        name: 'Tom',
        address: 'No. 189, Grove St, Los Angeles',
    },
    {
        date: '2016-05-02',
        name: 'Tom',
        address: 'No. 189, Grove St, Los Angeles',
    },
    {
        date: '2016-05-04',
        name: 'Tom',
        address: 'No. 189, Grove St, Los Angeles',
    },
    {
        date: '2016-05-01',
        name: 'Tom',
        address: 'No. 189, Grove St, Los Angeles',
    },
]
</script>
  

渲染正常:

分离配置文件

我们项目当中需要根据不同的需求配置不同的配置文件,常见的情况就是分离成:

一个测试的配置文件,一个是打包生产的配置文件 

在根目录新建一个 config 文件夹

在其下新建:webpack.common.ts 公共配置文件、webpack.dev.ts 测试环境配置文件、webpack.prod.ts 生成打包配置文件

 我们可以通过 webpack-merge 来帮我们合并两个配置信息:

npm i webpack-merge

webpack.common.ts   公共配置文件,配置基础的loader和插件 :

import * as path from 'path'
import * as HtmlWebpackPlugin from 'html-webpack-plugin'
import { VueLoaderPlugin } from 'vue-loader'
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'
import * as webpack from 'webpack'

export default {
    mode: 'development',//开发模式
    entry: './src/index.ts', //入口文件
    devtool: "inline-source-map",
    devServer: { // 开发服务器
        port: 8080
    },
    plugins: [   //插件
        new HtmlWebpackPlugin({
            template: path.join(__dirname, '../public/index.html')
        }),
        new VueLoaderPlugin(),
        new webpack.DefinePlugin({
            'process.env.API_URL': JSON.stringify(process.env.API_URL)
        })
    ],
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader',
                ]
            },
            {
                test: /\.s[ca]ss$/i,
                use: [
                    'style-loader',
                    'vue-style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
            {
                test: /\.js$/,
                loader: 'babel-loader'
            },
            {
                test: /\.(ts|tsx)$/,
                loader: "ts-loader",
                options: { appendTsSuffixTo: [/\.vue$/] }
            },
            {
                test: /\.(png|jpg|jpeg|gif|svg)$/i,
                type: 'asset',
            }
        ]
    },
    resolve: {
        plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })],
        // 添加“.ts”和“.tsx”作为可解析的扩展名
        extensions: [".ts", ".tsx", ".js"],
        // 添加对TypeScripts完全限定ESM导入的支持
        extensionAlias: {
            ".js": [".js", ".ts"],
            ".cjs": [".cjs", ".cts"],
            ".mjs": [".mjs", ".mts"]
        },
        alias: {
            '@': path.join(__dirname, '../src')
        },
    }
}

webpack.dev.ts   测试环境配置文件 :

import { merge } from 'webpack-merge'
import commonConfig from './webpack.common'
const devConfig: any = {
    mode: 'development',
    plugins: [
    ],
    devServer: {
        port: 8080, // 调试服务器的运行端口
        open: true, // 是否自动打开浏览器
        // 通常在开发环境下会出现跨域问题,在前端都是通过配置 proxy 解决,因为 jsonp 已经过时了
        proxy: {
            '/api': {
                target: 'http://localhost:8081',
                changeOrigin: true, 
                pathRewrite: {
                    '^/api': ''
                }
            }
        },
    },
}
module.exports = merge(commonConfig, devConfig)

webpack.prod.ts   生成打包配置文件 :

const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')
const devConfig = {
    mode: 'production',
    plugins: [
    ]
}
module.exports = merge(commonConfig, devConfig)

修改 package.json 的启动和打包脚本:
 

  "scripts": {
    "dev": "webpack serve --config ./config/webpack.dev.ts",
    "build": "webpack build --config ./config/webpack.prod.ts"
  },

配置 开发环境和生产环境的接口地址,在根目录下新建

.env.dev :

API_URL = http://localhost:3030

.env.prod :

API_URL = http://www.abc.com

使用 dotenv-webpack 进行配置,一个安全的webpack插件,支持dotenv和其他环境变量,并且只公开您选择和使用的内容。

dotenv-webpack - npm

npm i dotenv-webpack

声明模块:

declare module 'dotenv-webpack'

修改 webpack.dev.ts :

import { merge } from 'webpack-merge'
import commonConfig from './webpack.common'
import * as DotEnv from 'dotenv-webpack'
const devConfig: any = {
    mode: 'development',
    plugins: [
        new DotEnv({
            path: './.env.dev',
            safe: true
        })
    ],
    devServer: {
        port: 8080, // 调试服务器的运行端口
        open: true, // 是否自动打开浏览器
        // 通常在开发环境下会出现跨域问题,在前端都是通过配置 proxy 解决,因为 jsonp 已经过时了
        proxy: {
            '/api': {
                target: 'http://localhost:8081',
                changeOrigin: true,
                pathRewrite: {
                    '^/api': ''
                }
            }
        },
    },
}
module.exports = merge(commonConfig, devConfig)

修改 webpack.prod.ts :

import { merge } from 'webpack-merge'
import commonConfig from './webpack.common'
import * as DotEnv from 'dotenv-webpack'
const devConfig = {
    mode: 'production',
    plugins: [
        new DotEnv({
            path: './.env.prod',
            safe: true
        })
    ]
}
module.exports = merge(commonConfig, devConfig)

通过 process.env.API_URL 获取环境变量

配置好了开发的环境变量和生产的环境变量,打包的时候不需要修改代码

在webpack5当中,内置了一个 asset-module 模块, 方便我们在引入静态文件的时候进行打包或者是转换成base64 

修改 webpack.common.ts :

export default {
    module: {
        rules: [
            {
                test: /\.(png|jpg|jpeg|gif|svg)$/i,
                type: 'asset',
                // 设置 type 为 asset 让 webpack 按照静态文件的方式来处理文件
                generator: {
                    // 会给打包后的图片添加一串hash值
                    filename: 'static/imgs/[hash][ext]'
                },
                parser: {
                    dataUrlCondition: {
                        maxSize: 10 * 1024,
                        // 小于10kb的以上类型文件直接转换为 base64,否则单独生成一个文件
                        // 这样做,对于我们项目当中放多的小图片都不再打包成文
                        // 减少了打包的大小,并且减少了资源的链接消耗
                    }
                }
            }
        ]
    },
}

mini-css-extract-plugin

mini-css-extract-plugin - npm

npm i mini-css-extract-plugin

这个插件将CSS提取到单独的文件中。它为每个包含CSS的JS文件创建一个CSS文件。它支持CSS和SourceMaps的按需加载。 

修改 webpack.common.ts :

import * as MiniCssExtractPlugin from 'mini-css-extract-plugin'
export default {
    plugins: [ 
        new MiniCssExtractPlugin(),
    ],
}
npm run build 

开启持久化的存储缓存

export default {
    cache: {
        type: 'filesystem'// 缓存,提供二次打包速率
    }
}

开启之后的第一次打包所需时间是正常的,从第二次打包开始,打包的速度会有大幅的提高

项目源码--点这里

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue3是一种用于构建用户界面的JavaScript框架,它具有快速、灵活、可重用等特点。Webpack则是一种JS的打包工具,可以将多个JS文件打成一个JS文件。Vue-Router是Vue框架中的路由管理器,通过它可以实现前端路由的切换。Axios则是一种基于Promise的 HTTP 库,用于处理前端与后端的数据交互。Vuex则是Vue框架中的状态管理工具,将组件的共享状态抽取出来,以集中管理,便于开发人员管理。这些技术都是前端开发中必不可少的技术,用于优化前端项目的结构,提高开发效率。 在具体的项目开发中,为了提高代码的复用性,通常会对这些技术进行进一步的封装。对于Vue-Router,可以将项目的路由进行封装,创建一个Route.js文件,用于统一管理路由。通过这样的封装,可以使得路由的管理更加清晰。 对于Axios,可以通过封装一个API.js文件,将后端接口进行统一管理,减少代码的重复性。在API.js中可以封装所有后端接口的请求方法,统一处理请求返回的数据。 对于Vuex,则可以将项目的状态进行封装,写一个store.js文件,用于集中管理应用的状态。在store.js中可以设置全局数据,方便在各个组件中进行访问和修改。同时,也可以将状态的变化通过mutations.js文件封装,以保证数据的可靠性。 最后,使用Webpack进行打包。Webpack可以将多个JS文件打成一个JS文件,减少了请求的次数,提高了页面的加载速度。 综上所述,通过对Vue3、WebpackVue-Router、Axios、Vuex等技术的封装,可以提高代码的复用性和可维护性,从而加快项目的开发进度。同时,这些技术的结合还能够为项目提供更好的架构,提升用户的使用体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

subsistent

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值