在本章当中,我们不使用官方提供的 Vue-Cli,而是从头开始搭建,一步一步实现一个简易脚手架,理解 Vue-Cli 到底是怎么实现的(顺路了解一下 Webpack 在 Vue 项目中的使用)
源码可以见 基于 vue-cli 整合的一个个人脚手架
需要注意的是,
Webpack和Vue的版本均在2.0以上
创建目录
大致目录结构如下
1 | ├── index.html ==> 根本件,最后用于展示 App.vue 组件 |
首先新建一个 HTML 文件,添加一个 id 为 box 的容器
1 | // html |
然后在 main.js 文件中添加一点内容,用于最后的渲染
1 | // main.js |
接下来来安装 Webpack 和 webpack-dev-server,再配置一下 Webpack,先简单的指定一下入口和出口文件
1 | // webpack.config.js |
然后就可以在我们的 index.html 中引入出口文件中指定的 JavaScript
- 这里是
bundle.js,但是目录中不使用webpack -p的话是不存在这个文件的 Webpack会在编译执行的时候为我们自动生成该文件
1 | // index.html |
关于出口文件,如果想指定输出的目录,可以按照下面这样来设置
1 | output: { |
配置 vue-loader
如果需要解析像 App.vue 这样的文件,使其变成正常可以访问的代码,我们需要引入 vue-loader 来处理,这个时候我们就可以在 Webpack 中配置我们的相关 loader 了(这也是 Webpack 最核心的东西),在 webpack.config.js 中添加
1 | module: { |
配置完 Webpack 以后就可以来安装 vue-loader 以及其相关的一些组件了,单单使用 vue-loader 编译写入 .vue 文件是不够的,因为在 .vue 文件当中主要分为三大块,如下所示
1 | <template></template> |
每一部分都需要相对应的 loader 来进行处理,这时就需要同时安装以下 loader
1 | // 处理模版 |
可以使用以下命令来进行安装
1 | npm install vue-template-compiler css-loader vue-style-loader vue-hot-reload-api --save-dev |
配置 babel
众所周知,现在浏览器对 ES6 语法的支持还不是很完善,这个时候也就需要使用 Babel 来解析 ES6 语法,先来配置 Webpack
1 | module: { |
Babel 需要的相关组件如下
1 | babel-loader ==> 主程序 |
最后来汇总一下所有涉及到的依赖
1 | vue-loader ==> 编译写入 .vue 文件 |
启动
安装和配置完成以后,这个时候就可以来启动程序了,但是如果想在命令行直接使用类似 npm run dev 命令的话,就需要配置一下 package.json 文件,在 scripts 标签下设置
1 | // 设置 scripts 即可 |
然后就可以使用 npm run dev 命令来启动服务了,如果在控制台中看到
1 | Project is running at http://localhost:8080/ |
这个时候就表明启动成功了,可以访问 http://localhost:8080/ 来查看效果了,如果配置全部正确的话,就可以在浏览器中看到对应的内容了,修改内容直接保存,浏览器也会自动跟着刷新,如果在最后运行的时候发现控制台出现如下内容
1 | [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. |
这个就主要涉及到了 Vue 的运行时构建和独立构建的区别,简单来说,就是在独立构建的时候可以使用用 template 选项,而在运行时构建则不行,只能通过模板来编译转成 render 函数,两者区别如下
- 独立构建包含模板编译器,运行时构建不包含模板编译器
- 模板编译器的作用就是将
template选项编译成render函数,render函数是渲染的关键 - 鉴于以上两点,使用运行时构建时,不能出现
template选项- 因为此时没有模板编译器,但是有一种情况除外,即
webpack + vue-loader情况下单文件组件中出现template是可以的
- 因为此时没有模板编译器,但是有一种情况除外,即
- 使用
Vue-Cli生成项目时,会提醒使用哪种构建方式,npm包默认导出的是运行时构建- 如果需要使用独立构建,需要在
Webpack中配置alias
- 如果需要使用独立构建,需要在
目前暂时发现的两者的应用场景上的区别有
- 需要注意
Vue实例化时的方式,运行时构建方式下实例化Vue时,不要出现template属性 index.html中不要出现template或者是通过vue-router渲染的route-view- 以上区别讨论的场景均为使用
webpack + vue-loader单文件组件下
解决办法也很简单,只需在 Webpack 配置中设置一下 Vue 的别名即可
1 | resolve: { |
h => h(App)
在 vuejs 中,可以把 h 函数仅是作为 createElement 函数的缩写,所以上述代码可以理解为
1 | render: function (createElement){ |
render 方法
1 | render: function (createElement) { |
也是 2.0 新增的函数,可以直接给绑定节点渲染一个 Vue 组件,如果在 1.x 的版本下,就应该使用
1 | new Vue({ |
.babelrc
和 .bowerrc 是一样的原理,都是用来配置文件,只需要在根目录新建一个名为 .babelrc 文件,然后添加
1 | { |
就可以达到和上面一样的效果
url-loader
url-loader 是对 file-loader 的上层封装,比如可以在 Webpack 中对图片的加载器进行配置
1 | { |
这样一来,在小于 8K 的图片将直接以 base64 的形式内联在代码中,可以减少一次 HTTP 请求,所以在处理一般小图片的时候就可以使用 url-loader 来转为 base64,其他情况照常使用 file-loader
webpack 中的 loader 和 plugin
Webpack 是一个模块打包器(module bundler),提供了一个核心,核心提供了很多开箱即用的功能,同时它可以用 loader 和 plugin 来扩展,Webpack 常用配置包括 devtool、entry、output、module、resolve、plugins、externals 等,这里我们主要介绍 Webpack 常用的 loader 和 plugin
Webpack 允许我们使用 loader 来处理文件,loader 是一个导出为 function 的 Node.js 模块,可以将匹配到的文件进行一次转换,同时 loader 可以链式传递
使用方式
一般 loader 的使用方式分为三种,第一种,在 webpack.config.js 中配置(较多)
1 | module.exports = { |
第二种,通过命令行参数方式
1 | webpack --module-bind 'txt=raw-loader' |
第三种,通过内联使用
1 | import txt from 'raw-loader!./file.txt'; |
一些比较常用的 loader
- 样式有
style-loader、css-loader、less-loader、sass-loader等 - 文件有
raw-loader、file-loader、url-loader等 - 编译有
babel-loader、coffee-loader、ts-loader等 - 校验测试有
mocha-loader、jshint-loader、eslint-loader等
比如下面配置,可以匹配 .scss 的文件,分别经过 sass-loader、css-loader、style-loader 的处理
1 | module.exports = { |
style-loader,将创建一个style标签将CSS文件嵌入到HTML中css-loader,处理其中的@import和url()sass-loader,转化sass为CSS文件,并且包一层module.exports成为一个js module
其他一些相关 loader 介绍
vue-loader、coffee-loader、babel-loader- 等可以将特定文件格式转成
JavaScript模块 - 将其他语言转化为
JavaScript语言和编译下一代JavaScript语言(ES6)
- 等可以将特定文件格式转成
file-loader、url-loader- 可以处理(静态)资源
file-loader- 可以复制和放置资源位置,并可以指定文件名模板,用
Hash命名更好利用缓存
- 可以复制和放置资源位置,并可以指定文件名模板,用
url-loader- 可以将小于配置
limit大小的文件转换成内敛data url的方式,减少请求
- 可以将小于配置
raw-loader- 可以将文件以字符串的形式返回
imports-loader、exports-loader- 等可以向模块注入变量或者提供导出模块功能,常见场景是
jQuery插件注入$,imports-loader?$=jQuery- 禁用
AMD,imports-loader?define=false - 等同于
var $ = require('jQuery')和var define = false;
- 等可以向模块注入变量或者提供导出模块功能,常见场景是
expose-loader- 暴露对象为全局变量