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

协程苔原
• 阅读 5628

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 lang="scss">
                        sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' // <style lang="sass">
                    }
                }
            },
            {
                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 lang="scss">
                        sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' // <style lang="sass">
                    }
                }
            },
            {
                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是大同小异的,区别就讨论到这里了。如果文章觉得那里写得不好或者写错了,欢迎指出。同时也希望,这篇文章能帮到大家!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表(关于日期时间时分秒显示不出来)
在使用皕杰报表设计器时,数据据里面是日期型,但当你web预览时候,发现有日期时间类型的数据时分秒显示不出来,只有年月日能显示出来,时分秒显示为0:00:00。1.可以使用tochar解决,数据集用selecttochar(flowdate,"yyyyMMddHH:mm:ss")fromtablename2.也可以把数据库日期类型date改成timestamp
Easter79 Easter79
3年前
Vue+Webpack配置css
  使用VueWebpack搭建工程时,在webpack.config.js中的module的rules里针对各种文件配置加载工具。在针对css文件配置时遇到一个问题:打包构建时报错——Modulebuildfailed:Unknownword。  配置内容如下:{  test:/\.css$/,  use:
李志宽 李志宽
3年前
搭漏洞环境难?虚拟机/容器了解一下
前言先说说KaliLinux的一个问题,有些同学问我Kali环境怎么搭,他弄了好久都没配置好,安装过程老出错,我感觉非常惊讶。Kali虽然是点历史遗留问题,我在几年前玩的时候用ISO文件搭建也真的有很多坑,但是现在都阔以下载虚拟机版本的KaliVM呀,下载完一导入,改一下网卡,开箱即用。我把这个方法告诉他之后,他的表情是:还能这样操作?
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
KO
KOKO是一个基于Webpack开发的快速开始Web开发的脚手架工具,具有以下特性:可以当做一个Webpack配置种子来使用,无需二次配置、开箱即用自动支持多页应用(可选)Vue单文件组件的开发方式资源分块加载,内联和异步加载方式管理,低成本实现首屏优化支
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Wesley13 Wesley13
3年前
Java多线程导致的的一个事物性问题
业务场景我们现在有一个类似于文件上传的功能,各个子站点接受业务,业务上传文件,各个子站点的文件需要提交到总站点保存,文件是按批次提交到总站点的,也就是说,一个批次下面约有几百个文件。      考虑到白天提交这么多文件会影响到子站点其他系统带宽,我们将分站点的文件提交到总站点这个操作过程独立出来,放到晚上来做,具体时间是晚上7:00到早上7:00。
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(