webpack构建vue项目(再谈配置)

webpack配置起来确实麻烦,这不,以前用刚配好了vue1+的版本,结果在(部分)安卓机上测试,发现存在开启热加载(dev-server)的状况下不能识别vue语法的问题,试了不少方法,都没能很好的解决,最后索性将vue升级到2+,居然就能识别了,好吧!css

1.先分享一下webpack配置vue2+的一些不一样(本人亲测):html

(1)dependencies中的vue默认安装2+,直接运行,会报以下错:[Vue warn]: Failed to mount component: template or render function not defined。
若是dependencies中的vue选择^1.0.26,那么devDependencies中对应的vue-loader最好选择^7.3.0,vue-hot-reload-api最好选择^1.2.0,不然就会报错。
(2)若是vue选择安装1+,dependencies中的vue-router最好选择^0.7.13(默认安装2+,没法识别router.map()这个方法)。
(3)若是vue选择安装1+,dependencies中的vue-validator最好选择^2.0.0(默认安装2.1.7)。
(4)若是vue选择安装1+,后面在开启webpack dev server的时候,处于同一内网中的安卓手机访问本地设备的输出页面会出现不识别vue语法的兼容问题,ios手机能够正常访问和解析,可是开启别的server再来访问并不会出现这种兼容问题,因此为了测试方便,建议vue选择安装2.0的版本。
(5)若是vue选择安装2+,vue2.0有两种构建模式,默认状况下运行构建,可是不能解析单文件的template模板,因此要使用独立构建,须要在alias中指定vue$的模块别名地址,即vue

// 其余解决方案
resolve: {
    // require时省略的扩展名,遇到.vue结尾的也要去加载
    extensions: ['','.js', '.vue'],
    // 模块别名地址,方便后续直接引用别名,无须写长长的地址,注意若是后续不能识别该别名,须要先设置root
    root:"../node_modules",
    alias:{
        'vue$':'vue/dist/vue.js'
    }
}, 

(6)若是vue选择安装2+,对应的vue-validator就必须安装3+,不然会报错,可是这样一来在开启webpack dev server的时候,又会出现安卓手机不识别vue-validator的兼容问题,ios手机能够正常访问和解析,因此为了测试方便,改用其余的基于vue的表单验证插件,即vuerify,须要引入vue2+、vuerify和v-vuerify-next。
(7)若是vue选择安装2+,涉及到的loader尽可能升级到最新,不然会报错;最好是将vue升级到2.0.7,对应的vue-loader升级到8.5.4,vue-html-loader升级到1.2.3,vue-hot-reload-api升级到2.0.6。
(8)若是vue选择安装2+,对应的router要升级到2+,可是这时以前使用的表单验证插件就会作出问题(例如:vue-validator-3.0.0-alpha.1和vuerify+v-vuerify-next这两款插件在路由跳转的时候都会报错,尝试了不少方法都无济于事,感受仍是版本匹配的问题),awesome-vue集合了来自社区贡献的数以千计的插件和库,在这里我找了一些专门针对vue2+的表单验证插件,发现Vee-Validate和Vue-Easy-Validator这两款插件没有出现以前遇到的问题,并且前者的英文文档写得至关详细,赞之。node

2.不要小瞧版本匹配问题,webpack自带插件和第三方插件,vue和里面须要引入的插件,再加上各类模块加载器,有时匹配对了一个,另外一个又会出问题,我就是在这里浪费了太多的时间,最后索性跟着版本走,强势拥抱2+。关于vue2+的语法,官网里写得很详细,这里就不赘述,我仍是接着讲webpack配置问题吧:jquery

(1)配置文件里的入口和出口:webpack

// 入口文件,路径相对于本文件所在的位置,能够写成字符串、数组、对象
entry: {
    // 如下是单页面的入口路径
    index: path.resolve(__dirname, "../entry/index.js"),

    // 须要被提取为公共模块的群组
    vendors: ["vue","vue-router","vue-resource","vee-validate","jquery"],
},

// 输出配置
output: {
    // 输出的js文件,路径相对于本文件所在的位置
    path: path.resolve(__dirname, "../output/js/"),

    // 将入口文件中涉及到的同步加载的js文件打包成一个js文件,基于文件的md5生成hash名称的script来防止缓存
    filename: "[name].[hash].js",

    // 异步加载的业务模块,例如按需加载的.vue单文件组件
    chunkFilename: "[id].[name].[chunkHash].js"
}

这里须要注意的点很多,我主要说两个:ios

一个是publicPath,上次说过测试环境里写成 config.output.publicPath = "/",不建议在生产环境里动它,但最近导出文件的时候若是不设置publicPath,按需加载的.vue单文件组件中的script路径会报错,因此仍是得设置一下publicPath,其路径能够写成相对于生成的html单文件所在位置的相对路径;web

另外一个就是chunkFilename,上次没怎么提它,主要是没怎么用到它,若是项目里涉及到异步加载的业务模块,就不得不提它了。若是使用AMD风格的requireJS来实现路由组件的懒加载,例如:vue-router

const Register = resolve => require(["../src/private/components/register"],resolve);

这样写的话,这个组件就不会和entry中引入的js文件一块儿打包,而是单独打包成一个js文件,名字就是这里的chunkFilename,带一个自动分配的,可读性不好的[id]。若是想在命名的时候更有归属感,即带上一个[name],可使用require.ensure来实现路由组件的懒加载,例如:api

const Register = resolve => require.ensure(["../src/private/components/register"], () => resolve(require("../src/private/components/register")), "register");

若是要把某个路由下的全部组件都打包在同个异步chunk中,无须明确列出require.ensure的依赖,即传空数组就行。若是你还想在按需加载某个模块的同时执行一些代码,能够写成:

const Register = resolve => {
    require.ensure(["../src/private/components/register"], () => {
        // 这里能够写异步加载指定模块以前的代码
        resolve(require("../src/private/components/register"));
        // 这里能够写异步加载指定模块以后的代码
    },"register")
}

(2)在测试环境中写了 config.output.publicPath = "/" 以后,当前配置文件下的不少相对路径都是相对于这个来设定,即不少涉及到相对路径的地方须要发生相应的变化,不然开启dev-server以后会报错找不到文件的错误,那么有哪些地方须要改呢,我我的建议改如下几个地方:

某些模块加载器的路径,例如加载图片的url-loader和加载图标的file-loader;

某些插件的路径,例如生成单个html文件的HtmlWebpackPlugin,提取css单文件的ExtractTextPlugin

(3)为了防止“找不到favicon.ico文件”这种错误带来的干扰,找一张图塞到项目根目录下,输出的时候直接在 new HtmlWebpackPlugin 插件参数列中写 favicon: "favicon.ico",而后开启dev-server就不会报错啦,可是生产环境下仍是会报错,缘由是导出的位置和输出的js文件同级,因此得把它从新塞到和输出的html文件同级,这里我是用的CopyWebpackPlugin这款插件(第三方插件),代码以下:

// 把指定的文件复制到指定的目录
new CopyWebpackPlugin([
    // from写的是源文件名,这里的位置是在项目根目录下,to是写将要复制过去的目录位置,相对于输出的js文件
    {from:'favicon.ico',to:"../html/favicon.ico"}
])

(4)对于.vue单文件,css默认是内部样式,如今要把它里面的css提取出来变成外部导入,可是若是.vue单文件组件是按需加载,那么此设置无效,即会从新变回内部样式(也多是我本身弄错了),代码以下:

vue: {
    loaders: {
        css: ExtractTextPlugin.extract('vue-style-loader', 'css-loader'),
    }
}

(5)config.devtool这个就看本身喜爱吧,开发环境下推荐使用cheap-module-eval-source-map,生产环境下推荐使用cheap-source-map或source-map,后者获得的.map文件体积比较大,可是可以彻底还原之前的js代码

(6)若是要提取入口文件里面的公共模块,配置文件中必需要有如下三步:

entry: {
        // path.resolve([from ...], to) 将to参数解析为绝对路径
        index:path.resolve(__dirname, '.index.js'),
        // 须要被提取为公共模块的群组
        vendors:['vue','vue-router','jquery']
},
new webpack.optimize.CommonsChunkPlugin({
        name: 'vendors',
        filename: 'vendors.js',
}), 

第三步是 new HtmlWebpackPlugin 插件参数列里的chunks里必定要引入vendors;

(7)若是将css单独提取出来,配置文件中必需要有如下三步:

var ExtractTextPlugin = require('extract-text-webpack-plugin');
// module.loaders里添加
{
      test: /\.css$/,                  
      // loader: 'style-loader!css-loader',
      // 将样式抽取出来为独立的文件
      loader: ExtractTextPlugin.extract("style-loader", "css-loader"),
      exclude: /node_modules/
}
new ExtractTextPlugin("../css/[name].[contenthash].css")

3.其余须要注意的地方:

(1)html文件中最好只写和html相关的标签语言,尽可能不要导入外部的css或者js文件,也尽可能不要写内部样式或者在<script>标签里写js代码
(2)css文件中写url的时候注意路径问题,特别是在配置文件里设置了publicPath的状况下
(3)js文件中涉及到文件引入的,能够用require或define或import from,注意采用这种引入的前提是被引入文件已经进行了模块化的代码规范
(4)若是不想单独引入某个文件,能够在全局挂载插件中进行设置,区别于window挂载
(5)vue组件中涉及到图片路径(主要是src形式)报错的,能够在路径外层加上require(),这样测试环境下是没有问题的,可是生产环境下可能还会报错,关键在于弄清楚两种环境下图片的相对路径分别是相对于谁
(6)webpack加载css的时候,遇到font-family必定要去掉属性值的空格和双引号,否则解析出来的样式会出错

 

未完待续~

相关文章
相关标签/搜索