New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue 异步组件 #27

Open
zhongdeming428 opened this Issue Dec 1, 2018 · 0 comments

Comments

Projects
None yet
1 participant
@zhongdeming428
Copy link
Owner

zhongdeming428 commented Dec 1, 2018

最近在做一个 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);
        }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment