vue-cli3單頁構建大型項目方案

1、vue-cli3單頁面構建方案

一、在目標文件夾內執行

vue ui ; 一個ui版界面,用於建立vue項目;

二、打開router文件夾內的index,看狀況配置router的模式,是默認的hash仍是history?

ps:我的推介history模式,由於內嵌如app的H5頁面的話,有可能某些app是不容許頁面上帶有'#'的,而hash會在url上利用#來作路由轉發。
ps:history模式在發佈到服務器上須要nginx配置一下。詳情請自行百度。
const router = new VueRouter({
  base: '/',
  mode: 'history', //還可設置爲'hash'模式
  routes
})

三、在根目錄新建vue.config.js,覆蓋webpack配置,將以下內容copy到文件中,做爲初始配置

// const webpack = require('webpack')

module.exports = {
    lintOnSave: false, // 禁止eslint
    devServer: {
        open: true, // 構建完成自動打開瀏覽器
    },

    configureWebpack: {
        plugins: [
            // 全局配置node_modules中的模塊,使用時無需引入
            new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: "jquery",
                "windows.jQuery": "jquery"
            })
        ]

    },

    // webpack 連接 API,用於生成和修改 webapck 配置
    chainWebpack: (config) => {
        // 取消 chunks,每一個頁面只對應一個單獨的 JS / CSS
        config.optimization.splitChunks({
            cacheGroups: {}
        });

        // config
        //     .plugin('webpack-bundle-analyzer')
        //     .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
    },

    pluginOptions: {

    }

}

四、配置完這些後,npm run serve啓動項目,會加載以下兩個js

npm run serve

1.png

app.js:是全部單頁面首次渲染都必須加載的js,內部合併了框架及js(如vue、vue-x、vue-router及非異步組件但引用了的node_modules中的模塊),及全部頁面公用的模塊。

about.js:是每一個頁面獨立的js,這個跟router中引用模塊的方式有關。

具體詳解以下:

一、
import Home from '../views/Home.vue'
這種引用方式引用頁面模版組件,就不會出現about.js文件,由於屬於同步模塊,當前件建的js會被打包進app.js。可是此種隨着頁面的增多,公用的app.js會愈來愈大。看狀況在app.js大小接受的前提下權衡使用;
二、
const routes = [
  {
    path: '/',
    name: 'Home',
    // component: Home
    component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue') // webpack的魔法註釋,將拆分出的js命名爲home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]
這種引用方式就是異步引用模版組件,不會將當前組建的js打包進app.js,就不會出現1種的問題。由於只要沒有加載到對應頁面,就不會加載對應頁面的js。對應頁面的js會最爲獨立的js單獨的動態引入,如同上圖的about.js,在進入about頁面時纔會引入。
三、

若是在main.js中引入的node_modules包,則會直接打包進app.js,這個逃不掉。css

ps:最終結論,建議每一個頁面都異步引用頁面模版。

五、每一個頁面若是引了node_mudules就會存在相對應的vendors-home.js,若是沒引入node_mudules的話,每一個頁面按需組件就不會存在vendors-home.js這個文件,以下圖:

2.png
3.png

六、區分本地、測試、線上環境

ps:官網提供一種方案,可是須要創建多個環境配置的配置文件,嫌麻煩,就不使用官方的方式,使用以下插件拆分環境:
cross-env:https://github.com/kentcdodds/cross-env
cnpm i cress-env --save-dev // 更改node環境變量插件

以後在package.json中加入以下三行配置,便可區分本地、測試、線上環境html

"scripts": {
    "serve": "cross-env NODE_ENV=development vue-cli-service serve",
    "test": "cross-env NODE_ENV=test vue-cli-service build",
    "build": "cross-env NODE_ENV=production vue-cli-service build"
  },
在vue.config.js中執行以下代碼便可打印出當前環境。
console.log(process.env.NODE_ENV)
在src目錄下新建config目錄,進入目錄,新建gateway.config.js文件用於配置不一樣環境接口host,代碼以下:
gateway.config.js文件內容以下:
// 開發環境地址(npm run serve)
const devHost = {
  // 接口地址域名相關
  baseApi: 'https://abc.com',

}

// 測試環境地址(npm run test)
const testHost = {
  // 接口地址域名相關
  baseApi: 'https://abc.com',

}

// 線上環境地址(npm run build)
const proHost = {
  // 接口地址域名相關
  baseApi: 'https://abc1.com',

}

// 區分環境選擇靜態資源地址
const env = process.env.NODE_ENV

let exportConfig = ''
if (env === 'production') {
  exportConfig = proHost
} else if (env === 'test') {
  exportConfig = testHost
} else {
  exportConfig = devHost
}

export default exportConfig
結束:以後只須要在接口api的js文件中引入此文件便可。發佈時區分環境打包。

七、淺談項目引入第三方插件方案

ps:原則:移動端單個js大小不超過200k;pc端單個js不超過400k;
1.vue模塊化引入node_modules包插件:
前提,各個頁面都是異步加載,這樣的好處是單個頁面的js不會被打包進公共app.js中。以後在單個js中引入第三方庫。可是據測試:這種模塊化引入第三方插件,比cdn模式引入的js體積至少要大2唄,由於webpack內部對每一個第三方庫進行了二次處理,會增大js體積。權衡js大小使用。
2.cdn模式引入第三方插件:
提供這種方式,是由於有些庫是不支持vue的,只支持cdn模式引入,並且比較輕量級,能夠選擇這種方案,異步cdn模式引入第三方插件,這些方式最下方腳手架示例中都有demo;

八、項目中經常使用的打包插件及第三方庫

1.vue https://cn.vuejs.org
2.vue-router https://router.vuejs.org
3.vue-x https://vuex.vuejs.org
4.sass https://www.sass.hk
5.axios http://www.axios-js.com/
6.normalize.css http://necolas.github.io/normalize.css/
7.n-zepto https://npm.taobao.org/package/n-zepto
8.webpack-bundle-analyzer https://github.com/webpack-contrib/webpack-bundle-analyzer

下方是vue-cli3內置插件(直接在vue.config.js中配置):
以下插件可參考vue-cli3官網配置方法:

https://cli.vuejs.org/zh/config/#css-sourcemapvue

8.autoprefixer:自動添加瀏覽器前綴。(如:-webkit-等)
7.url-loader:改變靜態資源引用路徑
7.ProvidePlugin:全局配置node_modules中的模塊
具體配置方法以下(比較全的vue.config.js配置):
const webpack = require('webpack')

const processEnv = process.env.VUE_APP_ENV; // 區分環境(值:production、development、test)
const isPro = processEnv === 'production'; // 判斷production環境

const outputDir = 'dist'; // 輸出文件目錄(默認dist)
const assetsDir = ''; // 配置放置生成的靜態資源 (js、css、img、fonts) 的 (相對於 outputDir 的) 目錄

// 區分環境選擇cdn地址
let publicPath = '' // 靜態資源引用路徑
let fontPublicPath = '' // 字體圖標引用的cdn路徑
let imgPublicPath = '' // css引用圖片的cdn路徑(c2c/static/img)
if (processEnv === 'production') {
    publicPath = 'https://abc.com/c2c/shop' // 正式環境靜態資源css、js等cdn路徑
    fontPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}fonts` // 正式環境字體圖標引用的cdn路徑
    imgPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}/img` // 正式環境css引用圖片的cdn路徑
} else if (processEnv === 'test') {
    // publicPath = './' // 正式環境靜態資源css、js等cdn路徑
    publicPath = 'https://bcd.com/c2c/shop/dist' // 測試環境靜態資源css、js等cdn路徑
    fontPublicPath = ''
    imgPublicPath = ''
} else {
    publicPath = '/'
    fontPublicPath = ''
    imgPublicPath = ''
}

const devServerHost = 'localhost';
const devServerPort = '8080'; // 端口號
const devServerOpen = true; // 熱啓動後自動打開瀏覽器

module.exports = {

    // 配置生成dist裏面static的cdn資源路徑(測試環境爲./,正式環境走cdn路徑)
    publicPath: publicPath,

    // 輸出文件目錄(默認dist)
    outputDir,

    // 配置放置生成的靜態資源 (js、css、img、fonts) 的 (相對於 outputDir 的) 目錄
    assetsDir,

    devServer: {
        host: devServerHost,
        port: devServerPort,
        open: devServerOpen, // 構建完成自動打開瀏覽器


        // eslint檢測影響代碼編譯,註釋調不會影響代碼編譯
        // overlay: {
        //     warnings: true,
        //     errors: true
        // }
    },
    lintOnSave: processEnv === 'development' ? true : false, // 開發環境開啓eslint,測試和線上編輯代碼禁止eslint

    //  webpack 配置,鍵值對象時會合並配置,爲方法時會改寫配置
    configureWebpack: config => {
        // 擴展資源,不將部分資源js等打入包內引用cdn資源
        let externals = {
            // 'swiper': 'Swiper',
        };
        config.externals = externals;

        //警告 webpack 的性能提示
        config.performance = {
            hints: isPro ? 'warning' : false, // 本地開發不顯示警告
            // 入口起點的最大致積
            maxEntrypointSize: 512000, // 500kib
            // 生成文件的最大致積
            maxAssetSize: 307200, // 300kib
            // 只給出 js 文件的性能提示
            assetFilter(assetFilename) {
                return assetFilename.endsWith('.js');
            }
        };
    },

    // webpack 連接 API,用於生成和修改 webapck 配置
    chainWebpack: (config) => {
        // 取消 chunks,每一個頁面只對應一個單獨的 JS / CSS
        config.optimization.splitChunks({
            cacheGroups: {}
        });

        // 全局配置node_modules中的模塊,使用時無需引入
        config.plugin('provide').use(webpack.ProvidePlugin, [{
            $: "n-zepto",
            Zepto: "n-zepto",
            "window.Zepto": "n-zepto"
        }]);

        config.module
            .rule('images')
            .use('url-loader')
            .loader('url-loader')
            .tap(options => Object.assign(options, {
                limit: 10240, // 小於10k,壓縮圖片 => base64
                // limit: 3000,
                publicPath: imgPublicPath,
                name: `[name].[hash:8].[ext]`
            }))

        // 設置fonts字體文件引用的路徑
        config.module
            .rule('fonts')
            .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
            .use('url-loader')
            .loader('file-loader')
            .tap(options => Object.assign(options, {
                limit: 5000,
                publicPath: fontPublicPath,
                name: '[name].[hash:8].[ext]'
            }))


        // npm run report;打印app.js的模塊報告,查看各個模塊;
        if (processEnv === 'report') {
            config
                .plugin('webpack-bundle-analyzer')
                .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
        }

    },

    // css配置處理
    css: {
        // 是否使用css分離插件 ExtractTextPlugin;true:頁面css獨立分割,false:頁面css同一打包;
        extract: true,
        // 開啓 CSS source maps(默認false)線上關閉,測試和本地開啓
        sourceMap: isPro ? false : true,
        // css預設器配置項
        loaderOptions: {
            sass: {
                // sass的公共方法和變量,須要預編譯;
                prependData: `
                    @import "@/assets/css/global.scss";
                    @import "@/assets/css/func.scss";
                `
            },
            postcss: {
                plugins: [
                    // 瀏覽器自動加前綴
                    require('autoprefixer')({
                        overrideBrowserslist: [
                            "Android 4.0",
                            "iOS 7",
                            "Chrome > 31",
                            "ff > 31",
                            "ie >= 8"
                        ]
                    }),
                ]
            }

        },
        /** 啓用 CSS modules for all css / pre-processor files.
         引入第三方ui庫和若是在js中引用了css的話,必須設置爲true,由於若是設置爲false的話,會把這些經過js引入的css啓動css modules,會將第三方ui的css類名後面加上哈希值,會出問題。
         參考文檔(vue-cli官網解釋):https://cli.vuejs.org/zh/config/#css-requiremoduleextension 和
         https://cli.vuejs.org/zh/guide/css.html#css-modules
         **/
        requireModuleExtension: true
    },

    // 構建時開啓多進程處理 babel 編譯
    parallel: require('os').cpus().length > 1,

    pwa: {
        iconPaths: {
            favicon32: 'favicon.ico',
            favicon16: 'favicon.ico',
            appleTouchIcon: 'favicon.ico',
            maskIcon: 'favicon.ico',
            msTileImage: 'favicon.ico'
        },

    },

    // 第三方插件配置
    pluginOptions: {
        // ...
    }

}

九、一個基礎配置較爲完善的基於vue-cli3的單頁面項目方案腳手架:

項目腳手架集合project-init
其中的cli-start-spa文件夾,內部readme有項目細節。
相關文章
相關標籤/搜索