继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

vue+webpack搭建单文件应用和多文件应用webpack.config.js的写法区别

守候i
关注TA
已关注
手记 55
粉丝 1.7万
获赞 966

1.前言

这几天,都遇到过有人问过相似的问题,就是用vue和webpack搭建目录的时候,怎么把单页面应用的配置改成多文件应用,或者是怎么把多文件应用的配置改成单文件应用。这个情况,我之前有处理过,公司的同事教过我,我就针对这个情况写下此篇文章。各位如果觉得我哪里写得不够好,写错了,欢迎指出,大家一起进步。

2.说明

  1. 首先,我用的vue和webpack的版本都是2.x的,请大家留意自己使用的版本,特别是webpack的版本,1和2还是有些区别的。

  2. 然后,项目搭建的流程我不多说了,之前写过文章,网上也有很多好文章值得学习。接下来我只针对webpack.config.js这个配置文件说明,因为我做项目的时候,改动的基本就是这里,项目的文件虽然也有写法上的改动,但是那个改动相信不会难到大家,如果真的不知如何下手,我往后可能会再写文章。

3.单文件应用的配置

由于现在单文件应用写得比较多,一开始我就先放单文件应用的配置文件吧,代码如下

let path = require('path'); let webpack = require('webpack'); /*  html-webpack-plugin插件,webpack中生成HTML的插件,  具体可以去这里查看https://www.npmjs.com/package/html-webpack-plugin  */ let HtmlWebpackPlugin = require('html-webpack-plugin'); /*  一个根据模式匹配获取文件列表的node模块。  有关glob的详细用法可以在这里看到——https://github.com/isaacs/node-glob  */ let glob = require('glob'); /*  webpack插件  */ let CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; let UglifyJsPlugin = webpack.optimize.UglifyJsPlugin; let publicPath = '/dist/'; //IP地址 let serverHost = getIPAdress(); let config = {     //入口文件     entry: {         index: path.resolve(__dirname, 'src/js/page/index.js'),         vendors: ['vue', 'vue-router','vue-resource','vuex','element-ui','element-ui/lib/theme-default/index.css'] // 需要进行单独打包的文件     },     //出口文件     output: {         path: path.join(__dirname, 'dist'), //输出目录的配置,模板、样式、脚本、图片等资源的路径配置都相对于它         publicPath: publicPath,                //模板、样式、脚本、图片等资源对应的server上的路径         filename: 'js/[name].js',            //每个页面对应的主js的生成配置         // chunkFilename: 'js/[name].asyncChunk.js?[chunkhash]'   //chunk生成的配置         chunkFilename: 'js/[name].asyncChunk.js?'+new Date().getTime() //chunk生成的配置     },     module: {         //加载器         rules: [             {                 test: /\.vue$/,                 loader: 'vue-loader',                 options: {                     loaders: {                         scss: 'vue-style-loader!css-loader!sass-loader', // <style>                         sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' // <style>                     }                 }             },             {                 test: /\.html$/,                 loader: "raw-loader"             },             {                 test: /\.css$/,                 loader: 'style-loader!css-loader'             },             {                 test: /\.js$/,                 exclude: /node_modules/,                 loader: "babel-loader",                 options: {                     presets: ["es2015","stage-0"],                     plugins: ['syntax-dynamic-import']                 }             },             {                 test: /\.scss$/,                 loader: 'style-loader!css-loader!sass-loader'             },             {                 test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,                 loader: 'file-loader'             },             {                 //图片加载器,雷同file-loader,更适合图片,可以将较小的图片转成base64,减少http请求                 //如下配置,将小于8192byte的图片转成base64码                 test: /\.(png|jpg|gif)$/,                 loader: 'url-loader?limit=8192&name=images/[hash].[ext]'             }         ]     },     //插件     plugins: [         //生成HTML文件         new HtmlWebpackPlugin({             filename: path.resolve(__dirname, 'dist/html/index.html'), //生成的html存放路径,相对于path             template: path.resolve(__dirname, 'src/html/index.html'), //ejs模板路径,前面最好加上loader用于处理             inject: 'body',  //js插入的位置,true/'head'/'body'/false             chunks: ['load', 'vendors', 'vendor1', 'vendor2', 'index'],             hash: true         }),         //提取公共模块         new CommonsChunkPlugin({             name: 'vendors', // 将公共模块提取,生成名为`vendors`的chunk             //name: ['vendors', 'vendor1', 'vendor2', 'load'], // 将公共模块提取,生成名为`vendors`的chunk             minChunks: 2, //公共模块被使用的最小次数。配置为2,也就是同一个模块只有被2个以外的页面同时引用时才会被提取出来作为common chunks             // children:true  //如果为true,那么公共组件的所有子依赖都将被选择进来         }),         //在async chunk 里面找到复用 >= 2次的模块再单独提取出来         new CommonsChunkPlugin({             async: 'lazy',             minChunks: (module, count) => ( //count 模块被复用的次数                 count >= 2             )         }),         new UglifyJsPlugin({ //压缩代码             compress: {                 warnings: false,                 drop_debugger: true,                 drop_console: true             },             except: ['$super', '$', 'exports', 'require', 'define', 'module'] //排除关键字         })     ],     //使用webpack-dev-server     devServer: {         contentBase: path.join(__dirname, "/"),         host: serverHost,         port: 9090, //默认9090         inline: true, //可以监控js变化         hot: true//热启动     },     resolve: {         alias: {             vue: 'vue/dist/vue.js'         },         extensions:['.js','.scss','.vue','.json']// 可以不加后缀, 直接使用 import xx from 'xx' 的语法     } }; module.exports = config; /**  * @description 获取本地IP地址  * @returns {string|*}  */ function getIPAdress() {     let interfaces = require('os').networkInterfaces();     for (let devName in interfaces) {         let iface = interfaces[devName];         for (let i = 0; i < iface.length; i++) {             let alias = iface[i];             if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {                 return alias.address;             }         }     } }

4.多文件应用的配置

多文件现在用的不算很多,主要有时候会负责公司一些活动的小项目会用到,代码如下。

let path = require('path'); let webpack = require('webpack'); /*  html-webpack-plugin插件,webpack中生成HTML的插件,  具体可以去这里查看https://www.npmjs.com/package/html-webpack-plugin  */ let HtmlWebpackPlugin = require('html-webpack-plugin'); /*  一个根据模式匹配获取文件列表的node模块。  有关glob的详细用法可以在这里看到——https://github.com/isaacs/node-glob  */ let glob = require('glob'); /*  webpack插件  */ let CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; let UglifyJsPlugin = webpack.optimize.UglifyJsPlugin; let publicPath = '/dist/'; //通过getEntry函数获取所有js脚本 let jsEntries = getEntry('./src/js/page/*.js'); //IP地址 let IPAddress = getIPAdress(); let serverHost = IPAddress; let config = {     //入口文件     entry: jsEntries,     // entry: {     //     index:jsEntries,     //     vendors: ['vue', 'vue-router','vue-resource'] // 需要进行单独打包的文件     // },     //出口文件     output: {         path: path.join(__dirname, 'dist'), //输出目录的配置,模板、样式、脚本、图片等资源的路径配置都相对于它         publicPath: publicPath,                //模板、样式、脚本、图片等资源对应的server上的路径         filename: 'js/[name].js',            //每个页面对应的主js的生成配置         chunkFilename: 'js/[id].chunk.js?[chunkhash]'   //chunk生成的配置     },     module: {         rules: [             {                 test: /\.vue$/,                 loader: 'vue-loader',                 options: {                     loaders: {                         scss: 'vue-style-loader!css-loader!sass-loader', // <style>                         sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' // <style>                     }                 }             },             {                 test: /\.html$/,                 loader: "raw-loader"             },             {                 test: /\.css$/,                 loader: 'style-loader!css-loader'             },             {                 test: /\.js$/,                 exclude: /node_modules/,                 loader: "babel-loader",                 options: {                     presets: ["es2015","stage-0"],                     plugins: ['syntax-dynamic-import']                 }             },             {                 test: /\.scss$/,                 loader: 'style-loader!css-loader!sass-loader'             },             {                 test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,                 loader: 'file-loader'             },             {                 //图片加载器,雷同file-loader,更适合图片,可以将较小的图片转成base64,减少http请求                 //如下配置,将小于8192byte的图片转成base64码                 test: /\.(png|jpg|gif)$/,                 loader: 'url-loader?limit=8192&name=images/[hash].[ext]'             }         ]     },     plugins: [         new CommonsChunkPlugin({             name: 'vendors', // 将公共模块提取,生成名为`vendors`的chunk             //name: ['vendors', 'vendor1', 'vendor2', 'load'], // 将公共模块提取,生成名为`vendors`的chunk             minChunks: 2, //公共模块被使用的最小次数。配置为2,也就是同一个模块只有被2个以外的页面同时引用时才会被提取出来作为common chunks             // children:true  //如果为true,那么公共组件的所有子依赖都将被选择进来         })         new UglifyJsPlugin({ //压缩代码             compress: {                 warnings: false,                 drop_debugger: true,                 drop_console: true             },             except: ['$super', '$', 'exports', 'require', 'define', 'module'] //排除关键字         })     ],     //使用webpack-dev-server     devServer: {         contentBase: path.join(__dirname, "/"),         host: serverHost,         port: 9090, //默认9090         inline: true, //可以监控js变化         hot: true//热启动     },     resolve: {         alias: {             vue: 'vue/dist/vue.js'         },         extensions:['.js','.scss','.vue','.json']// 可以不加后缀, 直接使用 import xx from 'xx' 的语法     } }; //获取目录下的所有.html文件的名称 let tplPages = Object.keys(getEntry('./src/html/*.html')); tplPages.forEach((pathname)=> {     let conf = {         filename: path.resolve(__dirname, 'dist/html/'+ pathname +'.html'), //生成的html存放路径,相对于path         template: path.resolve(__dirname, 'src/html/'+ pathname +'.html'), //ejs模板路径,前面最好加上loader用于处理         inject: 'body',  //js插入的位置,true/'head'/'body'/false         chunks: ['load', 'vendors', 'vendor1', 'vendor2', 'index'],         hash: true     }; //如果文件名和入口文件名所对应的js有匹配(如:index.html和index.js就是相匹配的,就往index.html里面插入index.js;share.html和share.js就是相匹配的,就往share.html里面插入share.js)     if (pathname in config.entry) {         conf.inject = 'body';         conf.chunks = ['vendors', pathname];         conf.hash = true;     } //生成配置压栈     config.plugins.push(new HtmlWebpackPlugin(conf)); }); module.exports = config; /**  * @description 获取本地IP地址  * @returns {string|*}  */ function getIPAdress() {     let interfaces = require('os').networkInterfaces();     for (let devName in interfaces) {         let iface = interfaces[devName];         for (let i = 0; i < iface.length; i++) {             let alias = iface[i];             if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {                 return alias.address;             }         }     } } function getEntry(globPath) {     //获取globPath路径下的所有文件     let files = glob.sync(globPath);     let entries = {},         entry, dirname, basename, pathname, extname;     //循环     for (let i = 0; i < files.length; i++) {         entry = files[i];         dirname = path.dirname(entry);//返回路径的所在的文件夹名称         extname = path.extname(entry);//返回指定文件名的扩展名称         /**          * path.basename(p, [ext])          * 返回指定的文件名,返回结果可排除[ext]后缀字符串          * path.basename('/foo/bar/baz/asdf/quux.html', '.html')=>quux          */         basename = path.basename(entry, extname);         pathname = path.join(dirname, basename);//路径合并         entries[basename] = entry;     }     //返回map=>{fileName:fileUrl}     return entries; }

5.区别总结

一对比,区别就是出来了,但是写法是大同小异的。有区别是主要是下面几点

1.入口文件的区别,单页面应用入口文件是就是一个index.js('src/js/page/index.js')。而多页面应用的入口文件是所有需要用到的页面let jsEntries = getEntry('./src/js/page/*.js');。(getEntry方法是返回一个目录下所有的.js文件的名称和路径,jsEntries就是一个对象数组,里面包含着./src/js/page目录下所有的.js文件的名称和路径)

2.在多文件应用的配置中,HtmlWebpackPlugin这个插件是提取出来,在遍历getEntry('./src/html/*.html')的过程中,执行一次就往配置(config.plugins)那里push一次(config.plugins.push(new HtmlWebpackPlugin(conf)))。为什么这样写,大家应该很清楚了,有多少个入口文件,就得写多少次这个插件,new HtmlWebpackPlugin多少次,如果入口文件只有一两个,两三个还好,如果有100个入口文件,岂不是要在config.plugins那里写100次new HtmlWebpackPlugin,所以就标题文字遍历了,方便点。

结语

好了。单文件应用和多文件应用上,webpack.config.js是大同小异的,区别就讨论到这里了。如果文章觉得那里写得不好或者写错了,欢迎指出。同时也希望,这篇文章能帮到大家!


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP