美文网首页webpack
vue config.js和webpack 配置文件解读以及打包

vue config.js和webpack 配置文件解读以及打包

作者: super静_jingjing | 来源:发表于2019-02-25 17:32 被阅读0次

    最近把项目的所有配置文件都研究学习了一下,发现学无止境,永远都学不完呀,慢慢学吧。
    本来是想拿公司项目来简书记录学习过程,但是呢怕引起不必要的麻烦,所以就用了git大神的一个项目。
    大神的目录结构如下,我们主要看build/和package.json


    image.png

    package.json中配置了项目的基本信息、脚本以及包信息。我们主要看下脚本,如下


    image.png

    --------------------------------dev-----------------------------------
    先看“dev”(npm run dev),命令是:

    cross-env NODE_ENV=online node build/dev-server.js
    

    cross-env 跨平台设置及使用环境变量 ,即将环境变量 NODE_ENV设置为online
    node build/dev-server.js:执行build/dev-server.js
    分析dev-server.js:
    首先看一下build-server头部引入的文件


    image.png

    --> config是一个配置文件,后面会解析一下这个文件
    --> path:处理与路径转换
    express:Web应用框架
    webpack:打包工具
    opn: 用于打开浏览器
    http-proxy-middleware 用于把请求代理转发到其他服务器的中间件
    以上这些都是直接安装使用的
    -->./webpack.dev.conf : 自己写的的webpack配置文件,后面会详细解析
    ------config js

    var path = require('path')
    module.exports = {
        build: {
            // 修改环境为生产环境
            env: {
                NODE_ENV: '"production"'
            },
            //index  即打包后会生成启动首页,index.html
            index: path.resolve(__dirname, '../elm/index.html'),
            // 打包后 生成的资源存根目录
            assetsRoot: path.resolve(__dirname, '../elm'),
            //资源子目录
            assetsSubDirectory: 'static',
            //这个是通过http服务器运行的url路径,一般都是根目录
            assetsPublicPath: '/elm/',
            productionSourceMap: true,//设置成false,打包的体积会减小80%
            // 是否开启Gzip压缩
            productionGzip: false,
            // 需要使用 gzip 压缩的文件扩展名
            productionGzipExtensions: ['js', 'css']
        },
        dev: {
            env: {
                NODE_ENV: '"development"'
            },
            port: 8000,// 运行测试页面的端口
            assetsSubDirectory: 'static',// 编译输出的二级目录
            assetsPublicPath: '/',// 编译发布的根目录,可配置为资源服务器域名或 CDN 域名
            context: [ //代理路径
                '/shopping',
                '/ugc',
                '/v1',
                '/v2',
                '/v3',
                '/v4',
                '/bos',
                '/member',
                '/promotion',
                '/eus',
                '/payapi',
                '/img',
            ],
            proxypath: 'http://cangdu.org:8001',// 需要 proxyTable 代理的接口(可跨域)
            cssSourceMap: false
        }
    }
    

    config配置的目的都是为了服务webpack的配置,给不同的编译条件提供配置
    build: 打包上线的配置;可以看出会将打包好的文件放在elm目录下,启动的首页index,html,资源目录是elm/static
    dev:本地启动测试的配置;运行的端口8000

    ----- webpack.dev.conf
    webpack.dev中也引入了3个js,如下图


    image.png

    config.js已经在上部分看过,下面看下utils;
    ---->utils

    var path = require('path')
    var config = require('../config')
    //主要是为了抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象.
    var ExtractTextPlugin = require('extract-text-webpack-plugin')
    exports.assetsPath = function(_path) {
        var assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory
        //path.posix.join是path.join的一种兼容性写法,它的作用是路径的拼接,这里返回的是"XXX/XXX"
        // posix是跨平台兼容
        return path.posix.join(assetsSubDirectory, _path)
    }
    //生成cssloader表
    exports.cssLoaders = function(options) {
        options = options || {}
        function generateLoaders(loaders) {
            var sourceLoader = loaders.map(function(loader) {
                var extraParamChar
                if (/\?/.test(loader)) {
                    loader = loader.replace(/\?/, '-loader?')
                    extraParamChar = '&'
                } else {
                    loader = loader + '-loader'
                    extraParamChar = '?'
                }
                return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
            }).join('!')
            if (options.extract) {
                return ExtractTextPlugin.extract('vue-style-loader', sourceLoader)
            } else {
                return ['vue-style-loader', sourceLoader].join('!')
            }
        }
        return {
            css: generateLoaders(['css']),
            postcss: generateLoaders(['css']),
            less: generateLoaders(['css', 'less']),
            sass: generateLoaders(['css', 'sass?indentedSyntax']),
            scss: generateLoaders(['css', 'sass']),
            stylus: generateLoaders(['css', 'stylus']),
            styl: generateLoaders(['css', 'stylus'])
        }
    }
    //生成styleLoaders表
    exports.styleLoaders = function(options) {
        var output = []
        var loaders = exports.cssLoaders(options)
        for (var extension in loaders) {
            var loader = loaders[extension]
            output.push({
                test: new RegExp('\\.' + extension + '$'),
                loader: loader
            })
        }
        return output
    }
    

    utils比较简单,就是动态生成cssloader表,很多时候我们都是直接列出来,这边就是通过js的方式动态生成,其实是一样的。

    webpack.base.conf

    var path = require('path')
    var config = require('../config')
    var utils = require('./utils')
    var projectRoot = path.resolve(__dirname, '../')
    
    var env = process.env.NODE_ENV
    
    var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap)
    var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap)
    var useCssSourceMap = cssSourceMapDev || cssSourceMapProd
    module.exports = {
        //入口文件
        entry: {
            app: './src/main.js'
        },
        //导出配置
        output: {
            path: config.build.assetsRoot,
            publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
            filename: '[name].js'// [name]---entry中的key,即app.js
        },
        // 配置webpack如何寻找模块对应的文件。
        resolve: {
            //配置在查找文件的过程中用到的后缀列表
            extensions: ['', '.js', '.vue', '.less', '.css', '.scss'],
            //如果webpack 在 resolve.root 或者 resolve.modulesDirectories 实在找不到某个模块了,会去这个目录中找
            fallback: [path.join(__dirname, '../node_modules')],
            //alias通过别名来把原导入路径映射成一个新的导入路径
            alias: {
                'vue$': 'vue/dist/vue.common.js',
                'src': path.resolve(__dirname, '../src'),
                'assets': path.resolve(__dirname, '../src/assets'),
                'components': path.resolve(__dirname, '../src/components')
            }
        },
        //跟 resolve很像,但是是为loaders准备的。
        resolveLoader: {
            fallback: [path.join(__dirname, '../node_modules')]
        },
        //正常模块的配置
        module: {
            // loader
            loaders: [{
                test: /\.vue$/,
                loader: 'vue'
            }, {
                test: /\.js$/,
                loader: 'babel',
                include: projectRoot,
                exclude: /node_modules/
            }, {
                test: /\.json$/,
                loader: 'json'
            }, {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url',
                query: {
                    limit: 10000,
                    name: utils.assetsPath('img/[name].[ext]')
                }
            }, {
                test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                loader: 'url',
                query: {
                    limit: 10000,
                    name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
                }
            }]
        },
        vue: {
            loaders: utils.cssLoaders({
                sourceMap: useCssSourceMap
            }),
            postcss: [
                require('autoprefixer')({
                    browsers: ['last 10 versions']
                })
            ]
        }
    }
    

    以上配置就是开发环境和测试环境公用的配置,具体的意思见代码
    --->webpack.dev.conf

    var config = require('../config')
    var webpack = require('webpack')
    var merge = require('webpack-merge')//将对象or数组合并
    var utils = require('./utils')
    var baseWebpackConfig = require('./webpack.base.conf')
    var HtmlWebpackPlugin = require('html-webpack-plugin')
    
    Object.keys(baseWebpackConfig.entry).forEach(function(name) {
        baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
    })
    // baseWebpackConfig  entry: { app: [ './build/dev-client', './src/main.js' ]}
    
    module.exports = merge(baseWebpackConfig, {
        //module 配置如何处理模块。
        module: {
            loaders: utils.styleLoaders({
                sourceMap: config.dev.cssSourceMap
            })
        },
        // 使用eval-source-map,方便代码调试
        devtool: '#eval-source-map',
        //配置插件
        plugins: [
            // 可以简单的理解为将process.env 变成全局变量,可以在其他地方引用
            new webpack.DefinePlugin({
                'process.env': config.dev.env
            }),
            //根据模块调用次数,给模块分配ids,常被调用的ids分配更短的id,使得ids可预测,降低文件大小
            new webpack.optimize.OccurenceOrderPlugin(),
            //热更新--无刷新实现代码更新
            new webpack.HotModuleReplacementPlugin(),
            //跳过编译时出错的代码并记录,使编译后运行时的包不会发生错误
            new webpack.NoErrorsPlugin(),
            //生成html模版文件
            new HtmlWebpackPlugin({
                filename: 'index.html',
                template: 'index.html',
                favicon: 'favicon.ico',
                inject: true
            })
        ]
    })
    

    --------------------------------build----------------------------------
    看“ build”(npm run build),命令是:

    node build/build.js
    

    ----->webpack.prod.conf

    var path = require('path')
    var config = require('../config')
    var utils = require('./utils')
    var webpack = require('webpack')
    var merge = require('webpack-merge')
    var baseWebpackConfig = require('./webpack.base.conf')
    var ExtractTextPlugin = require('extract-text-webpack-plugin')
    var HtmlWebpackPlugin = require('html-webpack-plugin')
    var env = config.build.env
    var webpackConfig = merge(baseWebpackConfig, {
        module: {
            loaders: utils.styleLoaders({
                sourceMap: config.build.productionSourceMap,
                extract: true
            })
        },
        output: {
            path: config.build.assetsRoot,
            filename: utils.assetsPath('js/[name].js'),
            chunkFilename: utils.assetsPath('js/[name].[chunkhash].min.js')
        },
        vue: {
            loaders: utils.cssLoaders({
                sourceMap: config.build.productionSourceMap,
                extract: true
            })
        },
        plugins: [
           // 可以简单的理解为将process.env 变成全局变量,可以在其他地方引用
            new webpack.DefinePlugin({
                'process.env': env
            }),
            //对js进行压缩
            new webpack.optimize.UglifyJsPlugin({
                compress: {
                    warnings: false
                }
            }),
            //根据模块调用次数,给模块分配ids,常被调用的ids分配更短的id,使得ids可预测,降低文件大小
            new webpack.optimize.OccurrenceOrderPlugin(),
            // 抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象
            new ExtractTextPlugin(utils.assetsPath('css/[name].css')),
            //将生成的html模版和我们在output-filename生成的js产生关系,就是在让html启动引入js
            new HtmlWebpackPlugin({
                filename: config.build.index,
                template: 'index.html',
                inject: true,
                chunksSortMode: 'dependency'
            }),
            // 主要是用来提取第三方库和公共模块,即将公共模块提取到vendor.js中,
            //避免首屏加载的bundle文件或者按需加载的bundle文件体积过大,
            // 从而导致加载时间过长,着实是优化的一把利器。
            new webpack.optimize.CommonsChunkPlugin({
                name: 'vendor',
                minChunks: function(module, count) {
                    // any required modules inside node_modules are extracted to vendor
                    return (
                        module.resource &&
                        /\.js$/.test(module.resource) &&
                        module.resource.indexOf(
                            path.join(__dirname, '../node_modules')
                        ) === 0
                    )
                }
            }),
            // 将webpack的运行文件、第三方库和自定义公共模块单独抽离出
            // 避免webpack运行文件改变导致vendor.js改变,从而需要用户去重新加载
            new webpack.optimize.CommonsChunkPlugin({
                name: 'manifest',
                chunks: ['vendor']
            })
        ]
    })
    //是否使用productionGzip
    if (config.build.productionGzip) {
       //压缩
        var CompressionWebpackPlugin = require('compression-webpack-plugin')
      //配置中添加压缩的插件
        webpackConfig.plugins.push(
            new CompressionWebpackPlugin({
                asset: '[path].gz[query]',
                algorithm: 'gzip',
                test: new RegExp(
                    '\\.(' +
                    config.build.productionGzipExtensions.join('|') +
                    ')$'
                ),
                threshold: 10240,
                minRatio: 0.8
            })
        )
    }
    module.exports = webpackConfig
    

    ----->build.js

    require('shelljs/global')//允许直接在脚本中写shell命令
    env.NODE_ENV = 'production'
    
    var path = require('path')
    var config = require('../config')
    var ora = require('ora')//实现命令行环境的loading效果
    var webpack = require('webpack')
    var webpackConfig = require('./webpack.prod.conf')
    
    var spinner = ora('building for production...')
    spinner.start()//loading 开启
    
    var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
    // shell命令
    rm('-rf', assetsPath)
    mkdir('-p', assetsPath)
    cp('-R', 'static/*', assetsPath)
    //开始打包
    webpack(webpackConfig, function(err, stats) {
        spinner.stop()//loading 结束
        if (err) throw err
        process.stdout.write(stats.toString({
            colors: true,
            modules: false,
            children: false,
            chunks: false,
            chunkModules: false
        }) + '\n')
    })
    

    相关文章

      网友评论

        本文标题:vue config.js和webpack 配置文件解读以及打包

        本文链接:https://www.haomeiwen.com/subject/yxseyqtx.html