webpack搭建vue 项目的步骤
前期准备
由于本文内容是通过npm来加载vue,所以开始之前需安装nodejs环境,安装完成之后再执行以下步骤:
创建项目
mkdir vue-demo cd vue-demo
使用 npm init 命令 生成package.json文件
npm init
大概生成的package.json 如下:
{ "name": "vue-demo", "version": "1.0.0", "description": "this is a vue demo", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "license": "ISC", "dependencies": { } }
引入webpack ,关于如何使用webpack 请参考官网
npm install webpack --save-dev
如果使用npm下载的速度过慢,可以使用淘宝的cnpm 镜像
npm install -g cnpm Cregistry=https://registry.npm.taobao.org
输入以上命令即可将npm指向国内镜像,使用时需将npm 替换成cnpm即可, 其他不变
在项目中创建webpack.config.js 文件
const path = require('path') module.exports ={ entry:'./src/main.js', output:{ path:path.resolve(__dirname,'dist'), filename:"demo.js" } }
使用webpack 命令编译
webpack
编译之后的项目目录大概如下:
注意:在使用webpack命令之前 需先创建 index.html 和 main.js 文件 其中 main.js文件位于src 目录下
index.html 的内容如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue demo</title> </head> <body> <script src="./dist/demo.js"></script> </body> </html>
main.js 的内容如下
alert('hello world');
引入vue
npm install vue --save
执行命令后会在package.json中新增如下代码
"dependencies": { "vue": "^2.4.2" }
将main.js中的内容修改为如下代码
import Vue from 'vue' var vm = new Vue({ el:'#app', data:{ msg:'hello vue' } })
引入babel
npm install --save-dev babel-core babel-loader
由于在使用vue时会用到很多es6的语法,但是现在很多浏览器对es6的支持不是很好,所以在编译时需要将这些语法转换es5的语法,此时我们使用babel来进行编译。
babel的使用请阅读官网文档http://babeljs.cn/。
将babel加入到webpack.config.js 配置文件中:
const path = require('path') module.exports ={ entry:'./src/main.js', output:{ path:path.resolve(__dirname,'dist'), filename:"demo.js" }, module:{ rules:[ { test: /\.js$/, loader:"babel-loader", exclude: /node_modules/ } ] } }
然后命令行输入 webpack 命令即可进行编译,再编译完成后用浏览器打开index.html 文件,此时会发现浏览器控制台出现以下错误:
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build. (found in <Root>)
这是因为正在使用的是vue的运行时版本,而此版本中的编译器时不可用的,我们需要把它切换成运行时 + 编译的版本,需要在配置文件中添加如下代码
resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1 } }
此时在运行webpack 命令重新编译,编译后在访问index.html页面,页面内容如下图
此时一个基于webpack的vue 项目就搭建好。
webpack的一些常用配置
在项目的实际开发中我们还会引入css、图片以及字体等资源文件。这些文件的引入都需要相应的加载器才能将其加载到项目中并正常使用。
下面只介绍部分我们需要的加载器的使用方法, 更多信息请查阅webpack加载器文档。
css加载器
我们需要引入css-loader、和style-loader (安装style-loader的目的是为了在html中以style的方式嵌入css )。
执行命令
npm install --save-dev css-loader style-loader
在 webpack.config.js 中进行如下配置
module: { rules: [{ test: /\.js$/, loader: "babel-loader", exclude: /node_modules/ }, { test: /\.css$/, loader: 'style-loader!css-loader' }] },
然后再src 目录下 新建一个styles的文件夹并在里面添加一个main.css的文件,写上以下内容
#app{ color:red; }
然后再运行 webpack 命令, 并重新加载index.html 文件 ,可见css已经生效,效果如下图
图片资源的加载
使用file-loader或者url-loader加载器进行加载,他们都是用于打包文件和图片资源的,两者的区别是url-loader在file-loader的基础上进行了一次封装。
在访问网站时如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符,再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。
当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy。
此处我们使用url-loader,由于它是基于file-loader的封装,所以也需要引入file-loader。
npm install --save-dev file-loader url-loader
webpack.config.js 的rules 中增加如下配置
{ test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000 } }
接下来就是将图片引入到代码中,需要在main.js和index.html 分别作如下修改:
main.js
import Vue from 'vue' import './styles/main.css' import logo from'./images/logo.png' var vm = new Vue({ el:'#app', data:{ logo:logo, msg:'hello vue' } })
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue demo</title> </head> <body> <div id="app"> <img :src="logo" alt="logo" class="logo"> {{msg}} </div> <script src="./dist/demo.js"></script> </body> </html>
最后运行webpack 命令并访问 index.html ,结果如下
在测试中发现当图片大于10KB的时候发现加载图片失败,找不到图片,但此时在dist目录下面是能看到已经通过加载器加载成功了的图片,再通过浏览器的开发者工具对图片的引用路径进行检查时,可以发现页面中img的路径不对,路径中只有文件名缺失了前面的dist目录,所以此时我们需要将main.js中的代码进行如下修改
logo:"./dist/"+logo,
重新编译后图片就显示出来了。但是现在新的问题又出来了,由于我们在配置文件中配置了小于10kb的代码将以 base64的形式内联在代码中。所以此时是不需要 "./dist" 这个前缀的。 解决此问题有两种办法:
- 不使用base64的形式将图片内嵌到代码中
- 将html文件放到dist目录中 既然用了url-loader加载器则不推荐使用第一种。所以我们使用第二种方式。
将html文件放到dist目录中最简单的办法就是把index.html文件复制到dist目录中,然后将引入就是的代码改为:
<script src="./demo.js" > </script>
main.js中改回原来的设置
logo:logo,
重新编译后图片在两种情况下都可以加载出来了。
还有一中比较常用的方式是在编译时自动在dist的目录中创建一个html文件并将index.html中的内容复制过去。此时我们需要时webpack的 HtmlWebpackPlugin 插件。
HtmlWebpackPlugin 插件
引入插件
npm install --save-dev html-webpack-plugin
webpack.config.js 中增加如下配置
const HtmlWebpackPlugin = require('html-webpack-plugin') ... plugins:[ new HtmlWebpackPlugin() ]
重新编译后发现在dist目录下生成了如下内容的html的文件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack App</title> </head> <body> <script type="text/javascript" src="demo.js"></script></body> </html>
与我们原来自己的写index.html相比,该文件缺少了下面这些这些内容
<div id="app"> <img :src="logo" alt="logo" class="logo"> {{msg}} </div>
现在需要对配置文件做稍微的修改,让html文件在创建的时候自动将index.html的中内容复制过去。通过查阅该插件的文档,可知需做如下修改:
plugins:[ new HtmlWebpackPlugin({ title: 'vue demo', template: 'index.html' }) ]
index.html 文件中 去除 script代码,在重新编译后,即可获取我们需要的html文件
详细参数配置请参考官方文档
webpack-dev-server
在我们实际开发中需要将代码部署在server中,而不是在浏览器中直接打开文件。此时我们需要使用webpack的 webpack-dev-server 。
webpack-dev-server 为我们提供了一个简单的web服务器,并且能够实时重新加载(live reloading)。
npm install --save-dev webpack-dev-server
在webpack.config.js 文件中需要指定一个文件夹,告诉开发服务器需要从哪儿加载文件
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, 'dist'), filename: "demo.js" }, plugins: [ new HtmlWebpackPlugin({ title: 'vue demo', template: 'index.html' }) ], devServer:{ contentBase:"./dist" }, module: { rules: [{ test: /\.js$/, loader: "babel-loader", exclude: /node_modules/ }, { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000 } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000 } } ] }, resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1 } } }
上面红色字体的配置信息是告知webpack-dev-server, 在localhost:8080 下建立服务,将 dist 目录下的文件,作为可访问文件。
让我们在package.json中添加一个script脚本,可以直接运行开发服务器(dev server):
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev":"webpack-dev-server --open", "build": "webpack" },
然后输入如下命令
npm run dev
启动完成后,浏览器会自动打开一个访问 http://localhost:8080/ 的页面
此时服务已启动成功。
字体的加载
字体的加载方式与图片的一样也是用url-loader,配置如下
{ test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000 } }
vue-loader
在vue的开发过程中,通常我们需要写.vue结尾的文件即组件,如app.vue
<template> <div id="app"> <img src="./images/logo2.jpg" alt="logo" > {{msg}} </div> </template> <script> export default { name:'app', data(){ return { msg:"hello vue !!" } } } </script>
该文件需要通过vue-loader来进行加载,现在我们需要做如下配置。通过 vue-loader 和vue-template-compiler来加载并编译.vue文件
npm install --save-dev vue-loader vue-template-compiler
webpack.config.js 中
{ test: /\.vue$/, loader: 'vue-loader' }
为了在vue中引入对.vue的使用,我们需进行如下修改
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue demo</title> </head> <body> <div id="app"> </div> </body> </html>
main.js
import Vue from 'vue' import './styles/main.css' import App from './app.vue' new Vue({ el: '#app', template: '<App/>', components: { App } })
app.vue
<template> <div id="app"> <img src="./images/logo.png" alt="logo" > {{msg}} </div> </template> <script> export default { name:'app', data(){ return { msg: 'hello vue !!' } } } </script>
修改完成后 运行 npm run dev 命令 ,获得如下效果的页面
热部署
在上一步中,如果我们修改app.vue文件中的msg的参数,可以看到页面会自动刷新。但是此时是页面全局刷新的,如果我们只想局部刷新即只刷新修改的部分,需要使用webpack的HotModuleReplacementPlugin插件,在webpack.config.js的plugins中添加下面的信息:
new webpack.HotModuleReplacementPlugin()
然后去package.json中,script 里面dev的值中加上 --hot -only
"dev": "webpack-dev-server --hot-only --open",
然后重启服务,再修改 msg 的值,会发现此时值的改变是局部刷新的。
生产环境
如果我们在浏览器的控制台中发现有如下提示
意思时说项目现在运行在开发环境中,在部署到正式环境下时,要确保它是处于production的模式。需要将代码打包部署到生产环境时需要进行如下配置:
var webpack = require('webpack') module.exports = { // ... plugins: [ // ... new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ]}