webpack 是开发 vue.js 单页面应用程序的必要工具. 通过管理复杂的构建步骤, 它使您的开发工作流更加简单, 并且可以优化应用程序的大小和性能.
在本文中, 我将解释 Webpack 提升 vue 应用程序的四种方法, 包括:
单一文件组件
优化 Vue 构建
浏览器缓存管理
代码分离
vue-cli 怎么样?
如果您使用模板从 vue-cli 构建您的应用程序, 将提供一个预先制作的 Webpack 配置. 它们已经被很好地优化了, 而且我不能建议任何改进!
但由于它们的开箱即用效果非常好, 你可能对它们真正在做什么并不了解, 对吧? 考虑一下本文对 vue-cli 模板中使用的 Webpack 配置的概述, 因为它们包含了我在这里讨论的相同的优化.
一, 单一文件组件
Vue 的特性之一是使用 html 作为组件模板. 但是, 这些都有一个内在的问题: 要么 HTML 标记需要放在一个笨拙的 JavaScript 字符串中, 要么模板和组件定义需要放在单独的文件中, 这使得它们很难处理.
Vue 有一个优雅的解决方案, 称为单文件组件(SFCs), 其中包括模板, 组件定义和 CSS 都在一个整洁的. vue 文件中:
MyComponent.vue
- <template>
- <div id="my-component">...</div>
- </template>
- <script>
- export default {...}
- </script>
- <style>
- #my-component {...}
- </style>
SFCs 是由 vue-loader Webpack 插件实现的. 这个加载器将 SFCs 语言块分割开来, 并将每个块通过管道传输到一个适当的加载器, 例如脚本块传输到 babel-loader, 而模板块传输到 Vue 自己的 Vue -template-loader, 后者将模板转换成 JavaScript 呈现函数.
vue-loader 的最终输出是一个 JavaScript 模块, 可以包含在您的 Webpack 包中.
典型配置 vue-loader 如下:
- module: {
- rules: [
- {
- test: /\.vue$/,
- loader: 'vue-loader',
- options: {
- loaders: {
- // Override the default loaders
- }
- }
- },
- ]
- }
二, 优化 Vue 构建
运行时只构建
如果只在 Vue 应用程序 * 中使用呈现函数, 而没有 HTML 模板, 则不需要 Vue 的模板编译器. 您可以通过从 Webpack 构建中省略编译器来减小包的大小.
* 请记住, 单个文件组件模板是在开发中预编译来呈现函数的!
有一个只运行时构建的 Vue.JS 库, 它包含了 Vue.JS 的所有特性, 除了模板编译器 vue.runtime.JS. 它比完整的构建版本小大约 20KB, 所以如果可以的话值得使用.
默认情况下只使用运行时构建, 所以每次使用从 "vue" 导入 vue; 在你的项目中, 你会得到这样的结果. 不过, 您可以通过使用别名配置选项切换到另一个版本:
- resolve: {
- alias: {
- 'vue$': 'vue/dist/vue.esm.js' // Use the full build
- }
- },
删除生产中的警告和错误消息
另一种减少 Vue.JS 构建大小的方法是删除生产中的任何错误消息和警告. 这些代码使用不必要的代码使输出包的大小膨胀, 并且会导致最好避免的运行时成本.
如果检查 Vue 源代码, 您将看到警告块是以环境变量 process.env.node_env 的值为条件的, 例如:
- if (process.env.NODE_ENV !== 'production') {
- warn(("Error in" + info + ": \"" + (err.toString()) + "\""), vm);
- }
如果 process.env. 将 NODE_ENV 设置为 production, 然后可以在构建过程中通过一个缩小器自动将这些警告块从代码中删除.
您可以使用 DefinePlugin 来设置 process.env 的值. NODE_ENV 和 UglifyJsPlugin 来缩小代码并去掉未使用的块:
- if (process.env.NODE_ENV === 'production') {
- module.exports.plugins = (module.exports.plugins || []).concat([
- new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: '"production"'
- }
- }),
- new webpack.optimize.UglifyJsPlugin()
- ])
- }
三, 浏览器缓存管理
用户的浏览器将缓存站点的文件, 这样只有在浏览器还没有本地副本, 或者本地副本已经过期时, 它们才会下载.
如果您的所有代码都在一个文件中, 那么一个小小的更改就意味着需要重新下载整个文件. 理想情况下, 您希望用户尽可能少地下载, 因此明智的做法是将应用程序很少更改的代码与频繁更改的代码分开.
供应商文件
公共块插件可以将您的供应商代码 (例如依赖关系, 如 Vue.JS 库, 不太可能经常更改) 与您的应用程序代码 (代码可能在每次部署时更改) 解耦.
您可以配置插件来检查依赖项是否来自 node_modules 文件夹, 如果是, 则将其输出到一个单独的文件 vendor.JS:
- new webpack.optimize.CommonsChunkPlugin({
- name: 'vendor',
- minChunks: function (module) {
- return module.context && module.context.indexOf('node_modules') !== -1;
- }
- })
如果你这样做, 你现在有两个独立的文件在你的构建输出, 这将被浏览器独立缓存:
- <script src="vendor.js" charset="utf-8">
- </script>
- <script src="app.js" charset="utf-8">
- </script>
指纹识别
当构建文件发生更改时, 我们如何破坏浏览器的缓存?
默认情况下, 只有当缓存的文件过期或用户手动清除缓存时, 浏览器才会再次从服务器请求该文件. 如果服务器指示文件已更改, 则将重新下载该文件(否则服务器返回 HTTP 304 未修改).
为了保存不必要的服务器请求, 我们可以每次更改文件的内容时更改它的名称, 以迫使浏览器重新下载它. 一个简单的系统可以做到这一点, 就是在文件名中添加一个 "指纹", 方法是添加一个散列, 例如:
Common Chunks 插件会发出一个 "chunkhash", 如果文件的内容发生了变化, 它就会进行更新. Webpack 可以在文件名输出时附加这个散列:
- output: {
- filename: '[name].[chunkhash].js'
- },
当您这样做时, 您将看到您输出的文件的名称将类似于 App.3b80b7c17398c31e4705.JS.
自动注入构建文件
当然, 如果你添加了一个散列, 你就必须在索引文件中更新对文件的引用, 否则浏览器不会知道:
<script src="app.3b80b7c17398c31e4705.js"></script>
这将是一个非常单调乏味的手工任务, 所以使用 HTML Webpack 插件来为您完成它. 这个插件可以自动将对构建文件的引用注入到绑定过程中的 HTML 文件中.
首先删除对构建文件的引用:
index.HTML
- <!DOCTYPE HTML>
- <HTML>
- <head>
- <meta charset="utf-8">
- <title>
- test-6
- </title>
- </head>
- <body>
- <div id="app">
- </div>
- <!-- built files should go here, but will be auto injected -->
- </body>
- </HTML>
并将 HTML Webpack 插件添加到 Webpack 配置中:
- new HtmlWebpackPlugin({
- filename: 'index.html'
- template: 'index.html',
- inject: true,
- chunksSortMode: 'dependency'
- }),
现在, 带有散列的构建文件将自动添加到索引文件中. 此外, 您的 index.HTML 文件现在将包含在包输出中, 因此您可能需要告诉 Web 服务器它的位置已经更改.
四, 代码分离
默认情况下, Webpack 将把所有应用程序代码输出到一个大的包中. 但是, 如果你的应用程序有多个页面, 那么分割代码会更有效, 因此每个单独的页面代码都在一个单独的文件中, 并且只在需要时加载.
Webpack 有一个叫做 "代码分割" 的功能, 它就是这样做的. 在 Vue.JS 中实现这一点还需要异步组件, 使用 Vue 路由器甚至更容易.
异步组件
异步组件没有定义对象作为第二个参数, 而是有一个 Promise 函数来解析定义对象, 例如:
- Vue.component('async-component', function (resolve, reject) {
- setTimeout(() => {
- resolve({
- // Component definition including props, methods etc.
- });
- }, 1000)
- })
Vue 只在组件实际需要呈现时调用该函数. 它还将缓存结果, 以便将来重新呈现.
如果我们设计我们的应用程序, 使每个 "页面" 都是一个组件, 并将定义存储在服务器上, 那么我们就完成了代码分割的一半.
需要
要从服务器加载异步组件的代码, 请使用 Webpack require 语法. 这将指导 Webpack 在构建异步组件时将其捆绑到一个单独的捆绑包中, 更好的是, Webpack 将使用 Ajax 处理这个捆绑包的加载, 所以您的代码可以像这样简单:
- Vue.component('async-component', function (resolve) {
- require(['./AsyncComponent.vue'], resolve)
- });
延迟加载
在 Vue.JS 应用程序中, vue-router 通常是将 SPA 组织成多个页面的模块. 延迟加载是使用 Vue 和 Webpack 实现代码分割的一种正式方式.
- const HomePage = resolve => require(['./HomePage.vue'], resolve);
- const rounter = new VueRouter({
- routes: [
- {
- path: '/',
- name: 'HomePage',
- component: HomePage
- }
- ]
- })
来源: http://www.css88.com/web/vue-js/12364.html