Fork me on GitHub

Vue 异步组件

最近在做一个 Vue 项目的时候,突然发现了一个有意思的知识点。

有几位客服反馈说在点击某个链接跳转的时候,老是没得反应,导致选不了选项。我就很奇怪,内网环境下是没有问题的,所以代码出问题的可能性不大,怎么外网就有这种问题呢?后来仔细看了一下才发现,原来是运维那边出了点纰漏导致外网有些客户的 JavaScript 资源加载不出来,进而导致无法跳转。这里涉及到了 Vue 的异步组件知识,只有当切换到某个组件时,其单独打包的资源才会被加载。不同于统一打包的情况,这样做可以利用代码切割减少首屏加载时的资源大小,能够提升一定的加载速度,优化用户体验。接下来就自己重新做一下这个异步组件。

以下命令行操作均在 Linux 环境下进行。

一、搭建项目

先切换到你的项目根目录下,此时应该是一个空文件夹。

然后用 npm 命令初始化,添加具有一些默认选项的 package.json 文件。

$ npm init -y

然后开始创建必要的文件:

$ sudo touch .babelrc index.html

index.html 中写入一下代码,作为固定模板:

<!DOCTYPE html>
<html lang="zh-ch">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Async Components</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>

.babelrc 是配置 babel 转译器的,等会再来配置。

接下来创建必要的文件夹:

$ sudo mkdir -p build dist src/components src/routers 

在 build 目录下创建三个文件,作为 Webpack 打包的配置文件:

  • webpack.base.conf.js
  • webpack.dev.conf.js
  • webpack.prod.conf.js

然后安装必要的依赖:

$ npm i -D babel-loader@7 babel-core babel-preset-env webpack webpack-cli clean-webpack-plugin css-loader html-webpack-plugin vue-loader vue-style-loader vue-template-compiler webpack-dev-server webpack-merge

 

$ npm i -S vue vue-router

然后把下面的配置代码扔到对应的配置文件中:

// webpack.base.conf.js
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    target: 'web',
    entry: {
        index: path.resolve(__dirname, '../src/index.js')
    },
    output: {
        filename: '[name].[hash].js',
        path: path.resolve(__dirname, '../dist/')
    },
    resolve: {
        extensions: ['.vue', '.js', '.json', '.css'],
        alias: {
            '@': path.resolve(__dirname, '../src'),
            'vue': 'vue/dist/vue.js',
            'components': path.resolve(__dirname, '../src/components')
        }
    },
    node: {
        fs: 'empty'
    },
    module: {
        rules: [
          {
            test: /\.m?js$/,
            exclude: /node_modules/,
            use: 'babel-loader'
          },
          {
              test: /\.css$/,
              use: ['vue-style-loader', 'css-loader']
          },
          {
              test: /\.vue$/,
              use: 'vue-loader'
          }
        ]
    },
    plugins: [
        new htmlWebpackPlugin({
            inject: true,
            template: path.resolve(__dirname, '../index.html')
        }),
        new cleanWebpackPlugin(['dist'], {
            root: path.resolve(__dirname, '../'),
            verbose: true,
            dry: false
        }),
        new VueLoaderPlugin()
    ]
};

  

// webpack.dev.conf.js
const merge = require('webpack-merge');
const path = require('path');
const baseConfig = require('./webpack.base.conf.js');

module.exports = merge(baseConfig, {
    mode: 'development',
    devServer: {
        contentBase: path.resolve(__dirname, '../dist/'),
        port: 8888,
        open: true,
        // hot: true
        watchOptions: {
            watch: true
        }
    },
    devtool: 'inline-source-map'
});

  

// webpack.prod.conf.js
const merge = require('webpack-merge');
const path = require('path');
const baseConfig = require('./webpack.base.conf.js');

module.exports = merge(baseConfig, {
    mode: 'production',
    devtool: 'source-map'
});

具体怎么配置这里就不赘述了,之前也写过这类型的博客,可以参考一下:基于 Webpack 4 搭建 Vue 开发环境

然后配置 babel:

在 .babelrc 中写入以下内容:

{
    "presets": [
        "babel-preset-env"
    ]
}

然后就可以准备开发了。

二、开始 Vue 开发。

在 src 目录下创建一个 index.js 文件作为打包入口文件,然后:

// /src/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App';
import routerConfig from '@/routers';

Vue.use(VueRouter);
const routers = new VueRouter(routerConfig);

new Vue({
    el: '#app',
    components: { App },
    router: routers,
    template: '<div><App/></div>'
});

其中引用了一个同级目录下的 App 作为子组件,App.vue 代码:

<template>
    <div>
        <router-view></router-view>
        <router-link to="/javascript">JavaScript</router-link>
        <router-link to="/java">Java</router-link>
        <router-link to="/python">Python</router-link>
    </div>
</template>

<script>
    export default {
        name: 'app'
    }
</script>

<style scoped>
    h1 {
        color: blue
    }
</style>

注意到我们的 Vue-Router 配置写在 /src/routers/index.js 中,代码如下:

module.exports = {
    mode: 'hash',
    routes: [
        {
            path: '/javascript',
            component: (resolve) => {require(['components/javascript'], resolve)}
        },
        {
            path: '/java',
            component: (resolve) => {require(['components/java'], resolve)}
        },
        {
            path: '/python',
            component: (resolve) => {require(['components/python'], resolve)}
        },
        {
            path: '/*',
            redirect: '/javascript'
        }
    ]
}  

然后在 components 目录下写我们对应的三个组件:

// java.vue
<template>
    <h1>Java</h1>
</template>

<script>
export default {
    name: 'java'
}
</script>
// javascript.vue
<template>
    <h1>JavaScript</h1>
</template>

<script>
export default {
    name: 'javascript'
}
</script>
// python.vue
<template>
    <h1>Python</h1>
</template>

<script>
export default {
    name: 'python'
}
</script>

修改 npm scripts

npm scripts 的定义如下:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --config ./build/webpack.dev.conf.js",
    "build": "webpack --config ./build/webpack.prod.conf.js"
},

最后运行起来本地测试服务器:

$ npm run dev

打开浏览器的开发者工具,切换到 Network 选项卡,点击不同的链接,可以看到在加载切换路由时,会加载对应打包出来的 js 资源。

截图

运行 npm run build,可以看到打包出来了多个 js 资源文件:

截图

总结

  • 是一个 Webpack 打包 Vue 项目的优化点,通过异步组件,可以切割我们的代码,提升用户体验。

  • 异步组件切割代码实现简单,只需要改变配置 Vue-Router 的方式即可,指定路由对应的组件时,使用如下方式:

    {
        path: '/XXX',
        component: resolve => {
            require(['./XXX.vue'], resolve);
        }
    }
    

      

posted @ 2018-12-01 17:56  钟衷7  阅读(653)  评论(0编辑  收藏  举报