详解从零搭建 vue2 vue-router2 webpack3 工程


Posted in Javascript onNovember 22, 2017

以新手视角,详细介绍各个步骤内容,不深入讲步骤涉及的原理,主要介绍如何操作。

初始化工程

新建工程目录 vue2practice,在目录下执行npm init -y来创建一个 package.json,在 package.json 中先添加以下必备模块:

{

 "name": "vue2-vue-router2-webpack3",

 "version": "1.0.0",

 "devDependencies": {

  "vue": "^2.4.2",

  "vue-loader": "^13.0.2",

  "vue-router": "^2.7.0",

  "vue-template-compiler": "^2.4.2",

  "webpack": "^3.4.1",

  "webpack-dev-server": "^2.6.1"

 }

}

其中 vue-template-compiler 是 vue-loader 的 peerDependencies,npm3 不会自动安装 peerDependencies,然而 vue-template-compiler 又是必备的,那为什么作者不将其放到 dependencies 中呢?有人在 github 上提过这个问题,我大致翻译一下作者的回答(仅供参考):这样做的原因是因为没有可靠的方式来固定嵌套依赖的关系,怎么理解这句话?首先 vue-template-compiler 和 vue 的版本号是一致的(目前是同步更新),将 vue-template-compiler 指定为 vue-loader 的 dependencies 并不能保证 vue-template-compiler 和 vue 的版本号是相同的,让用户自己指定版本才能保证这一点。查看作者的回答(英文) 。如果两者版本不一致,运行时会出现下图所示的错误提示。

详解从零搭建 vue2 vue-router2 webpack3 工程

新建目录结构如下,新增的目录及文件先空着,后面的步骤会说明添加什么内容。

vue2pratice

  |-- package.json

  |-- index.html     // 启动页面

  |-- webpack.config.js // webpack配置文件

  |-- src

    |-- views    // vue页面组件目录

    |-- main.js   // 入口文件

    |-- router.js  // vue-router配置

    |-- app.vue   // 工程首页组件

配置Webpack

Webpack 默认读取 webpack.config.js,文件名不能随便改,其中 entry 是必须配置的。

module.exports = {

  entry: './src/main.js',

  output: {

    path: __dirname + '/dist',

    publicPath: '/static/',

    filename: 'build.js'

  }

}

Webpack 2+ 要求output.path必须为绝对路径。

配置 webpack-dev-server,只需在 package.json 添加以下启动命令即可。

"scripts": {

 "dev": "webpack-dev-server --hot --open"

}

webpack-dev-server 2 默认为 inline 模式,热模块替换仍需自己设置。

验证配置

在 index.html 中添加测试代码,引入打包后的 JS 文件。

<body>

  Hello, Webpack 3.

  <br>

  <script src="/static/build.js"></script>

</body>

在 main.js 中添加测试代码。

// main.js

document.write('来自main.js的问候!')

执行下面的命令来安装模块并启动服务器。

// 安装依赖

npm install

 

// 运行

npm run dev

启动后浏览器会自动打开http://localhost:8080,如果控制台没有报错,页面正确显示 main.js 和 index.html 的内容,改动 main.js 后浏览器不刷新能看到效果,则表示配置没问题。

详解从零搭建 vue2 vue-router2 webpack3 工程

Vue

新建页面

在 views 目录下新建 index.vue。

<template>

  <div>

    这是{{page}}页面

  </div>

</template>

<script>

export default {

  data: function () {

    return {

      page: 'index'

    }

  }

}

</script>

webpack 1 需要特定的 loader 来转换 ES 2015 import/export,webpack 2 起可以开箱即用。但是 ES6 的新语法还是需要 loader 来转换,在没有配置前,先不要用新语法。用了也没报错(比如 let,const等),那是因为你的浏览器已经支持了 ES6 语法(新版本浏览器都已经支持)。

配置路由

将 vue-router 实例化传入的参数new VueRouter(参数)提取到 router.js 形成路由配置文件。

import index from './views/index.vue'

export default {

  routes: [

    {

      path: '/index',

      component: index

    }

  ]

}

从 vue-loader@13.0.0,不能用 require 来引入 .vue 文件,因为 .vue 文件最终会被编译成 ES6 module。

首页

首页引入 ouput 配置的 JS,添加 Vue 实例的挂载目标。

<body>

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

<script src="/static/build.js"></script>

</body>

入口JS完成路由配置、初始化 Vue 实例。

import Vue from 'vue';

import VueRouter from 'vue-router';

import App from './app.vue';

import routerConfig from './router';

Vue.use(VueRouter);

var router = new VueRouter(routerConfig)

new Vue({

  el: '#app',

  router: router,

  render: h => h(App)

});

从 Vue 2.2.0 后使用 require('vue') 会报错,应使用 ES6 module(import),具体原因请参考 Vue 更新说明 https://github.com/vuejs/vue/releases,截图如下:

详解从零搭建 vue2 vue-router2 webpack3 工程

在首页组件 app.vue 中添加路由链接、路由视图组件。

<template>

  <div>

    <div>

      <router-link to="/index">Home</router-link>

    </div>

    <div>

      <router-view></router-view>

    </div>

  </div>

</template>

配置loader

配置 vue 文件对应的 loader。

module: {

  rules: [

    {

      test: /\.vue$/,

      use: ["vue-loader"]

    }

  ]

}

Webpack2 必须在 module.rules 下配置 loader。'-loader'不能省略,必须将 loader 名写全。可以使用 Rule.use 或 Rule.loader 来配置 loader(Rule.loader 是 Rule.use: [ { loader } ] 的简写),建议用 use。

上面完成了新增页面及访问该页面所需的配置,下面来测试下是否能正常访问/index。执行npm run dev,浏览器显示如图界面。

详解从零搭建 vue2 vue-router2 webpack3 工程

支持CSS

安装 css-loader 后即可在 vue 文件中使用

npm i css-loader -D

想要支持import / require引入CSS文件,则需要配置对应的 Rule。

{

  test: /\.css$/,

  use: ["vue-style-loader", "css-loader"]

}
<script>

import "../style/style.css"

</script>

支持CSS预处理语言

以 stylus 为例,安装 stylus 及 stylus-loader。

npm install stylus stylus-loader -D

增加 .styl 文件对应的 loader 配置。

{

  test: /\.styl$/,

  use: ["vue-style-loader", "css-loader", "stylus-loader"]

}

使用示例:

<style lang="stylus">

  .stylus

    .red

      color red

</style>

<script>

  import "../css/stylus-example.styl"

</script>

node-sass 安装慢的解决办法

详解从零搭建 vue2 vue-router2 webpack3 工程

使用淘宝镜像:

npm set disturl https://npm.taobao.org/dist

也可以单独设置node-sass镜像:

npm set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass

支持图片及图标字体

安装图片及图标字体依赖的loader。

npm install url-loader file-loader -D

增加图片及图标字体的loader配置。

{

  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,

  use: [{

    loader: "url-loader",

    options: {

      limit: 10000,

      name: 'images/[name].[hash:7].[ext]'  // 将图片都放入images文件夹下,[hash:7]防缓存

    }

  }]

},

{

  test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,

  use: [{

    loader: "url-loader",

    options: {

      limit: 10000,

      name: 'fonts/[name].[hash:7].[ext]'  // 将字体放入fonts文件夹下

    }

  }]

}

构建

添加打包命令如下:

"build":"webpack --progress --colors"

执行npm run build开始构建,完成后,可以看到工程目录下多了dist目录以及 dist/build.js。 

使用 Webpack 插件

压缩JS

在之前的文章提到过,打开未压缩版的build.js,你会发现ES6的语法没有被转化为ES5,因此需要安装babel 套件来完成语法的转化,否则压缩的时候就会报错。之前广泛使用的转码规则为 babel-preset-es2015,但 Babel 的官网上在9月宣布 ES2015 / ES2016/ ES2017 等等 ES20xx 时代的 presets 通通被废弃(deprecated),取而代之的是 babel-preset-env,并且承诺它将成为“未来不会过时的(future-proof)”解决方案。

npm i babel-loader babel-core babel-preset-env -D

增加babel的配置文件.babelrc。

{

  "presets": [

    ["env", { "modules": false }]

  ],

  "comments": false

}

将 modules 设置为 false,即交由 Webpack 来处理模块化,通过其 TreeShaking 特性将有效减少打包出来的 JS 文件大小,可以自行对比下前后打包出来的文件的大小,效果还是不错的。

comments 即是否保留注释。

接着配置 JS 文件的 loader。

{

  test: /\.js$/,

  use: "babel-loader",

  include: [path.resolve(__dirname, 'src')]

}

注意:Webpack2建议尽量避免exclude,更倾向于使用include。

压缩 JS 采用webpack.optimize.UglifyJsPlugin,配置如下:

new webpack.optimize.UglifyJsPlugin()

官网称warnings默认为false,你可能会遇到即使没有配置warnings: true,控制台仍显示警告,看下面这段源码就知道了。查看源码

详解从零搭建 vue2 vue-router2 webpack3 工程

只有当options.compress !== false时 warnings 才会被设置默认值 false,所以一旦配置了 compress 其它选项,那就需同时配置warnings: false。

warnings作用是当插件在压缩过程中移除的无效代码或定义是显示警告信息(display warnings when dropping unreachable code or unused declarations etc.)。

提取CSS

使用extract-text-webpack-plugin插件提取CSS。更改 css 及 less 的 loader 配置如下。

// 安装插件

npm i extract-text-webpack-plugin -D
// var ExtractTextPlugin = require("extract-text-webpack-plugin")

{

  test: /\.css$/,

  use: ExtractTextPlugin.extract({

    use: "css-loader"

  })

},

{

  test: /\.styl$/,

  use: ExtractTextPlugin.extract({

    use: ["css-loader", "stylus-loader"]

  })

}

上述配置并不能提取 vue 文件中的 style,需要设置 vue-loader 参数才可以。

{

  test: /\.vue$/,

  use: {

    loader: "vue-loader",

    options: {

      loaders: {

        css: ExtractTextPlugin.extract({

          use: 'css-loader'

        }),

        stylus: ExtractTextPlugin.extract({

          use: ["css-loader", "stylus-loader"]

        })

      }

    }

  }

}

初始化插件,filename 可以指定 CSS 文件的目录。

new ExtractTextPlugin({

  filename: "css/style.css"

})

PostCSS

安装 postcss-loader 及 postcss 插件。

npm i postcss-loader cssnano -D

配置 loader 如下:

// css-loader配置改为

use: ['css-loader', "postcss-loader"]

// stylus-loader配置改为

use: ["css-loader", "postcss-loader", "stylus-loader"]

postcss-loader 要放在 css-loader 和 style-loader 之后,CSS 预处理语言 loader 之前(stylus-loader)。

新增 postcss.config.js 来配置postcss插件,这样就不用给每个 postcss-loader 去配置。更多 postcss-loader 的配置方式请参考 postcss-load-config。

module.exports = {

  plugins: [

    require('cssnano')

  ]

}

cssnano 使用了一系列 postcss 插件,包含了常用的 autoprefixer 等,如何传入 autoprefixer 的配置?

require('cssnano')({

  autoprefixer: {

    add: true,

    browsers: ['> 5%']

  }

})

其中有一个插件 postcss-zindex 使用中发现有些问题。如果想禁用这个插件的话,配置如下:

require('cssnano')({

  zindex: {

    disable:true

  }

})

附:postcss插件分类搜索网站:http://postcss.parts/

生成首页

安装 html-webpack-plugin 插件。

npm i html-webpack-plugin -D

初始化插件。

// var HtmlWebpackPlugin = require('html-webpack-plugin');

new HtmlWebpackPlugin({

  filename: 'index.html',

  template: 'index.tpl.html'

})

其它插件

Webpack3 新增的作用域提升。

new webpack.optimize.ModuleConcatenationPlugin()

指定生产环境,以便在压缩时可以让 UglifyJS 自动删除代码块内的警告语句。

new webpack.DefinePlugin({

  'process.env.NODE_ENV': JSON.stringify('production')

})

因为这个插件直接做的文本替换,给定的值必须包含字符串本身内的实际引号。通常,有两种方式来达到这个效果,使用 '"production"', 或者使用 JSON.stringify('production')。

你完全可以在自己的代码中使用process.env.NODE_ENV来区分开发和生产,从而针对不同的环境做一些事情。不用担心这部分代码会被保留,最终会被 UglifyJS 删除。例如:

if (process.env.NODE_ENV != "production") {

  // 开发环境

}

// webpack.DefinePlugin插件替换后,上述代码会变成

if ("production" != "production") {

  // 开发环境

}

// 输出

if (false) {

  // 开发环境

}

// UglifyJS 会删除这段无效代码

使用上述插件后再次构建,会发现生成的JS相比原来的体积小了不少。

friendly-errors-webpack-plugin 是一个更友好显示 webpack 错误信息的插件。插件 github 地址:https://github.com/geowarin/friendly-errors-webpack-plugin

一般在开发环境下使用。

var FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

 

var webpackConfig = {

 // ...

 plugins: [

  new FriendlyErrorsWebpackPlugin(),

 ],

 // ...

}

效果如下图:

详解从零搭建 vue2 vue-router2 webpack3 工程

显示构建进度插件:webpack.ProgressPlugin

{

 // ...

 plugins: [

  new webpack.ProgressPlugin(),

 ],

 // ...

}

效果如下图:

详解从零搭建 vue2 vue-router2 webpack3 工程

美化 webpack 编译控制台打印的信息的插件webpack-dashboard

详解从零搭建 vue2 vue-router2 webpack3 工程

分离Webpack配置

将开发和生产配置文件分离,方便增加各个环境下的个性配置。Webpack2文档中也详细阐述了如何为多环境配置webpack。基本思路如下:

  1. 编写一个基本配置文件(webpack.base.config.js)
  2. 使用webpack-merge合并这个基础配置和针对环境的特定的配置(webpack.dev.config.js,webpack.prod.config.js)

webpack.base.config.js 内容如下:

var webpack = require('webpack');

var path = require('path');

var utils = require('./utils');

function resolve(relPath) {

  return path.resolve(__dirname, relPath);

}

module.exports = {

  entry: { app: resolve('../src/main.js') },

  output: {

    filename: 'js/[name].js'

  },

  module: {

    rules: [{

        test: /\.js$/,

        use: "babel-loader",

        include: [resolve('../src')]

      },

      {

        test: /\.vue$/,

        use: {

          loader: "vue-loader",

          options: utils.vueLoaderOptions()

        }

      },

      {

        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,

        use: {

          loader: "url-loader",

          options: {

            limit: 10000,

            name: 'images/[name].[hash:7].[ext]'

          }

        }

      },

      {

        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,

        use: [{

          loader: "url-loader",

          options: {

            limit: 10000,

            name: 'fonts/[name].[hash:7].[ext]'

          }

        }]

      }

    ]

  }

}

为什么要将vue-loader的options提取出来?其主要是用来配置CSS及CSS预处理语言的loader,开发环境可以不用配置,但是生产环境需要提取CSS、增加postcss-loader等,因此需要提取出来针对不同环境返回相应的options。后面会列出utils.vueLoaderOptions的内容。

为什么没有配置CSS的loader?理由和上面的vue-loader一样。

为什么没有配置path和publicPath?一方面是个性化参数,另外开发和生产可能不相同,因此在webpack.dev.config和webpack.prod.config中分别配置更为合适。

webpack.dev.config.js 内容如下:

var webpack = require('webpack');

var merge = require('webpack-merge');

var HtmlWebpackPlugin = require('html-webpack-plugin');

var baseWebpackConfig = require('./webpack.base.config');

var utils = require('./utils');

var config = require('./config');

Object.keys(baseWebpackConfig.entry).forEach(function(name) {

  baseWebpackConfig.entry[name] = [

    `webpack-dev-server/client?http://localhost:${config.dev.port}/`,

    "webpack/hot/dev-server"

  ].concat(baseWebpackConfig.entry[name])

});

module.exports = merge(baseWebpackConfig, {

  output: {

    path: config.dev.outputPath,

    publicPath: config.dev.outputPublicPath

  },

  module: {

    rules: utils.styleLoaders()

  },

  plugins: [

    new webpack.HotModuleReplacementPlugin(),

    new HtmlWebpackPlugin({

      filename: 'index.html',

      template: 'index.html',

      inject: true

    })

  ]

})

添加了HtmlWebpackPlugin后,index.html中就不需要在自己去引用打包的JS了,会自动根据打包的JS添加引用,这样更加方便,关于HtmlWebpackPlugin的配置,需要说明两点:

1.template的路径是相对于webpack编译时的上下文目录,说白了就是项目根目录,因此上面可以直接配置index.html,其指向的就是根目录下的index.html;

2.filename则是相对于webpack配置项output.path(打包资源存储路径)。

html-webpack-plugin关于template和filename路径源码如下:

// https://github.com/jantimon/html-webpack-plugin/blob/master/index.js

// template

this.options.template = this.getFullTemplatePath(this.options.template, compiler.context);

// filename

this.options.filename = path.relative(compiler.options.output.path, filename);

config.js内容如下:

module.exports = {

  dev: {

    outputPath: path.resolve(__dirname, '../static'),

    outputPublicPath: '/',

    port: 8000

  },

  prod: {

    outputPath: path.resolve(__dirname, '../static'),

    outputPublicPath: '/static/'

  }

}

utils.js内容如下:

var ExtractTextPlugin = require('extract-text-webpack-plugin');

var isProd = process.env.NODE_ENV === "production";

// 根据项目需求添加CSS预处理语言并安装相应的loader,以stylus-loader为例

var cssLang = [{

  name: 'css',

  reg: /\.css$/,

  loader: 'css-loader'

}, {

  name: 'stylus',

  reg: /\.styl$/,

  loader: "stylus-loader"

}];

function genLoaders(lang) {

  var loaders = ['css-loader', 'postcss-loader'];

  if (lang.name !== 'css') {

    loaders.push(lang.loader);

  }

  if (isProd) {

    // 生产环境需要提取CSS

    loaders = ExtractTextPlugin.extract({

      use: loaders

    });

  } else {

    // 开发环境需要vue-style-loader将CSS提取到页面头部

    loaders.unshift('vue-style-loader');

  }

  return loaders;

}

// 各种CSS的loader

exports.styleLoaders = function() {

  var output = [];

  cssLang.forEach(lang => {

    output.push({

      test: lang.reg,

      use: genLoaders(lang)

    })

  })

  return output;

};

// vue-loader的options

exports.vueLoaderOptions = function() {

  var options = {

    loaders: {}

  };

  cssLang.forEach(lang => {

    options.loaders[lang.name] = genLoaders(lang);

  });

  return options;

}

接下来就是如何启动webpack-dev-server,vue-cli的webpack模板工程用的express及webpack中间件做开发服务器,其实用webpack-dev-server就能满足需求,当然用express能够做更多的事情,毕竟webpack-dev-server是一个轻量级的express。dev.js内容如下:

var webpack = require('webpack');

var webpackDevServer = require('webpack-dev-server');

var devConfig = require("./webpack.dev.config");

var config = require("./config");

var compiler = webpack(devConfig);

var server = new webpackDevServer(compiler, {

  hot: true,

  noInfo: true,

  publicPath: config.dev.outputPublicPath,

  stats: { colors: true }

});

server.listen(config.dev.port, "0.0.0.0");

var url = `http://localhost:${config.dev.port}/`;

// 需先安装 opn 模块 npm i opn -D

var opn = require('opn');

// 打包完毕后启动浏览器

server.middleware.waitUntilValid(function() {

  console.log(`> Listening at ${url}`);

  opn(`${url}`);

})

生产配置文件(webpack.prod.config.js)内容如下:

// 设定为生产环境

process.env.NODE_ENV = 'production';

var webpack = require('webpack');

var merge = require('webpack-merge');

var HtmlWebpackPlugin = require('html-webpack-plugin');

var ExtractTextPlugin = require('extract-text-webpack-plugin');

var baseWebpackConfig = require('./webpack.base.config');

var utils = require('./utils');

var config = require('./config');

 

module.exports = merge(baseWebpackConfig, {

  output: {

    path: config.prod.outputPath,

    publicPath: config.prod.outputPublicPath

  },

  module: {

    rules: utils.styleLoaders()

  },

  plugins: [

    new webpack.DefinePlugin({

      'process.env.NODE_ENV': '"production"'

    }),

    new webpack.optimize.UglifyJsPlugin(),

    new ExtractTextPlugin({

      filename: "css/style.css?[contenthash:8]"

    }),

    new HtmlWebpackPlugin({

      filename: 'index.html',

      template: 'index.html',

      inject: true

    })

  ]

})

生产构建(prod.js)内容如下:

var webpack = require("webpack");

var webpackProdConfig = require('./webpack.prod.config');

webpack(webpackProdConfig, function(err, stats) {

  process.stdout.write(stats.toString());

});

对应在package.json中添加开发和生产构建的命令如下:

"scripts": {

  "dev": "node build/dev.js",

  "build": "node build/prod.js"

}

代码分割

参照vue-cli及webpack文档的提取公共代码的方式,利用插件webpack.optimize.CommonsChunkPlugin将来自node_modules下的模块提取到vendor.js(一般来讲都是外部库,短时间不会发生变化)。于是有如下代码:

new webpack.optimize.CommonsChunkPlugin({

  name: 'vendor',

  minChunks: function(module, count) {

    return module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0

  }

})

如果你查看未压缩版的vendor.js,会发现不仅包含vue的代码,还包含了webpackBootstrap(webpack模块加载器)的代码,按理说放在vendor里面也没啥问题,毕竟后面的模块都需要依赖于此,但是如果你的chunk使用了hash,一旦app代码发生了改变,相应的hash值会发生变化,webpackBootstrap的代码也会发生变化(如图),而我们提取vendor的初心就是这部分代码改变频率不大,显然这不符合我们的目标,那么应当将webpackBootstrap再提取到一个文件中,代码如下:

new webpack.optimize.CommonsChunkPlugin({

  name: 'manifest',

  chunks: ['vendor']

})

详解从零搭建 vue2 vue-router2 webpack3 工程 

用 import 还是 require

vue 2.2.0 后不能直接使用 require 来加载 vue,那么到底改是该使用 ES6 Module 还是 CommonJS 呢?,先看一个对比图:

全部使用 ES6 Module,即import、export default,最终打包的app.js为1.20KB。

详解从零搭建 vue2 vue-router2 webpack3 工程

全部使用 CommonJS(除了vue),即require、module.exports,最终打包的app.js为1.12KB。

详解从零搭建 vue2 vue-router2 webpack3 工程

虽然两者大小相差不大,但是这不禁让人觉得用 CommonJS 似乎是一条优化措施,那么代码层面到底是怎么回事呢?

为了一探究竟,注释了压缩插件,以about.vue最终构建的代码来看,使用 CommonJS 的代码如下:

(function (module, exports, __webpack_require__) {

 "use strict";

 module.exports = {

  data: function data() {

   return {

    page: 'about'

   };

  }

 };

}),

这基本上和 about.vue 中的代码相差无几,而使用 ES6 Module 构建的代码如下:

(function (module, exports, __webpack_require__) {

 "use strict";

 Object.defineProperty(exports, "__esModule", {

  value: true

 });

 exports.default = {

  data: function data() {

   return {

    page: 'about'

   };

  }

 };

}),

对比两种规范下构建后的代码,使用 ES6 Module 主要是多了 Object.defineProperty 那一部分,从而导致了最终打包的文件大一点儿。那是不是为了最终文件体积能小些就全部使用 CommonJS 呢?这个需要你充分理解 CommonJS 和 ES6 Module 的区别,引用《ECMAScript 6入门》这本书的解释如下:

ES6模块加载的机制,与CommonJS模块完全不同。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。

为了更清楚的理解这段话,我们稍微做一下测试,在 src 下增加一个test.js,内容如下(分别将两种写法列出):
 

// CommonJS

var counter = 1;

function incCounter() {

  counter++;

}

module.exports = {

  counter: counter,

  incCounter: incCounter,

};

// ES6 Module

export let counter = 1;

export function incCounter() {

  counter++;

}

在about.vue中测试如下:

// CommonJS

var test = require('../test');

export default {

  created() {

    console.log(test.counter); // 1

    test.incCounter();

    console.log(test.counter); // 1

  }

}

// ES6 Module

import { counter, incCounter } from '../test';

export default {

  created() {

    console.log(counter); // 1

    incCounter();

    console.log(counter); // 2

  }

}

最终的输出值也印证了前面的解释,更详细的解读请查阅相关资料或书籍。只有深入理解了两者的区别,自然就能明白何时该使用何种规范。当然 ES6 作为未来的趋势,我们应该去做更多的尝试。

异步组件(懒加载)

之前用懒加载的方式是:require.ensure,在 webpack2 中引入了 Code Splitting-Async 的新方法 import(),用于动态引入 ES Module。require.ensure 可以指定 chunkFilename,但是 import 没有很好的途径去指定,webpack3 为了解决这个问题,提出了用魔法注释的方式来指定模块名。

结合 vue-router 可以轻松实现懒加载,配置路由指向异步组件即可实现懒加载,比如:

{

    path: '/async',

    component: () => import(/* webpackChunkName: "async" */'./views/async.vue')

}

如果你发现使用 import() 运行时报错,有几种情况:
1.babel presets 配置为 es2015,则不支持动态导入功能,因此需要安装支持动态导入的 presets(npm i babel-preset-stage-2 -D),或者 babel 插件(npm i babel-plugin-syntax-dynamic-import -D);
2.babel presets 配置为 env,但是 modules 配置为 false,babel 则不会解析 import,可以安装插件 (npm i babel-plugin-syntax-dynamic-import -D)解决。

魔法注释虽然指定了块名,但是 webpack 默认的块名配置为 [id].js,即用的模块的 id 作为块名,因此需要我们手动改下配置。

修改 webpack.base.config.js 的 output:

output: {

  filename: 'js/[name].js',

  chunkFilename: "js/[name].[chunkhash].js"

}

效果如下图:

详解从零搭建 vue2 vue-router2 webpack3 工程 

如果发现魔法注释没有生效,要检查下 .babelrc 的配置项 comments 是否设为 true。或者不配置 comments(默认为true)

extract-text-webpack-plugin 默认不会提取异步模块中的 CSS,需要加上配置:

new ExtractTextPlugin({

  allChunks:true,

  filename: "css/style.css?[contenthash:8]"

})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
IE与Firefox下javascript getyear年份的兼容性写法
Dec 20 Javascript
Js中setTimeout()和setInterval() 何时被调用执行的用法
Apr 12 Javascript
JavaScript 创建运动框架的实现代码
May 08 Javascript
JS取request值以及自动执行使用示例
Feb 24 Javascript
jquery实现的Banner广告收缩效果代码
Sep 02 Javascript
JavaScript判断图片是否已经加载完毕的方法汇总
Feb 05 Javascript
JavaScript实现横线提示输入验证码随输入验证码输入消失的方法
Sep 24 Javascript
javascript实现圣旨卷轴展开效果(代码分享)
Mar 23 Javascript
基于JavaScript 实现拖放功能
Sep 12 Javascript
基于Vue+ElementUI的省市区地址选择通用组件
Nov 20 Javascript
vue 如何使用递归组件
Oct 23 Javascript
Ajax常用封装库——Axios的使用
May 08 Javascript
利用vue+elementUI实现部分引入组件的方法详解
Nov 22 #Javascript
通过一个简单的例子学会vuex与模块化
Nov 22 #Javascript
第一个Vue插件从封装到发布
Nov 22 #Javascript
详细分析单线程JS执行问题
Nov 22 #Javascript
jquery实现回车键触发事件(实例讲解)
Nov 21 #jQuery
Angular实现双向折叠列表组件的示例代码
Nov 21 #Javascript
bootstrap表格内容过长时用省略号表示的解决方法
Nov 21 #Javascript
You might like
法兰绒滤网冲泡
2021/03/03 冲泡冲煮
详解PHP中strlen和mb_strlen函数的区别
2014/03/07 PHP
ThinkPHP的cookie和session冲突造成Cookie不能使用的解决方法
2014/07/01 PHP
php绘制一条弧线的方法
2015/01/24 PHP
thinkPHP中多维数组的遍历方法
2016/01/09 PHP
关于Yii2框架跑脚本时内存泄漏问题的分析与解决
2019/12/01 PHP
实现点击列表弹出列表索引的两种方式
2013/03/08 Javascript
jQuery制作简单柱状图实例
2015/01/28 Javascript
JavaScript控制网页平滑滚动到指定元素位置的方法
2015/04/17 Javascript
jQuery+PHP实现可编辑表格字段内容并实时保存
2015/10/09 Javascript
js判断当前页面用什么浏览器打开的方法
2016/01/06 Javascript
利用JS轻松实现获取表单数据
2016/12/06 Javascript
使用vue-router设置每个页面的title方法
2018/02/11 Javascript
vue :src 文件路径错误问题的解决方法
2018/05/15 Javascript
如何用JavaScript实现功能齐全的单链表详解
2019/02/11 Javascript
jQuery AJAX与jQuery事件的分析讲解
2019/02/18 jQuery
JS实现无限轮播无倒退效果
2020/09/21 Javascript
vue实现验证用户名是否可用
2021/01/20 Vue.js
node.js文件的复制、创建文件夹等相关操作
2021/02/05 Javascript
Python查询阿里巴巴关键字排名的方法
2015/07/08 Python
详解python中的 is 操作符
2017/12/26 Python
详解如何将python3.6软件的py文件打包成exe程序
2018/10/09 Python
python使用pipeline批量读写redis的方法
2019/02/18 Python
Python解析json时提示“string indices must be integers”问题解决方法
2019/07/31 Python
python手机号前7位归属地爬虫代码实例
2020/03/31 Python
Keras 数据增强ImageDataGenerator多输入多输出实例
2020/07/03 Python
css3中less实现文字长阴影(long shadow)
2020/04/24 HTML / CSS
Android本地应用打开方法——通过html5写连接
2016/03/11 HTML / CSS
联想韩国官网:Lenovo Korea
2018/05/10 全球购物
六道php面试题附答案
2014/06/05 面试题
承诺书范本大全
2015/05/04 职场文书
焦裕禄观后感
2015/06/03 职场文书
英雄儿女观后感
2015/06/09 职场文书
加薪申请书应该这样写!
2019/07/04 职场文书
nginx处理http请求实现过程解析
2021/03/31 Servers
python中使用redis用法详解
2022/12/24 Redis