博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
webpack实战(二):真实项目中应用系统配置
阅读量:6997 次
发布时间:2019-06-27

本文共 11424 字,大约阅读时间需要 38 分钟。

hot3.png

字数:2061

阅读时间:15分钟

环境:webpack3.8.1

前言

本文续接文章:

上篇文章讲的是框架的配置方案,本文讲的是应用系统的配置方案。

这里,我们先梳理一下框架和应用的关系。这里我在框架配置中自定义了一个webpack插件,其作用就是生成一个loader.js文件,应用系统直接在页面中加载该文件,就会自动加载框架相应的资源文件。即,我们这里的目的是让不同的应用系统可以使用同一份框架资源,从而减轻部署压力。因此,我们所有的配置也是建立在这个基础之上。

其次,由于我们的应用系统配置项大同小异,所以,所有的应用系统会有一个公共的配置文件。

正文

应用系统的基本目录结构如下:

-all	-build		-common			-webpack.common.config.js			-webpack.dev.config.js			-webpack.prod.config.js	-app1		-build			-webpack.config.js	-app2	-app3

all文件夹中放置这所有的应用系统文件。其下build文件夹放置所有应用系统的公共配置,app1、app2、app3分别表示不同的应用系统文件夹。在应用系统文件夹中,有一个build文件夹,放置应用系统的webpack配置文件。

接下来我们就分别按照如上文件,一一讲解。

文件名 作用
all/build/common/webpack.common.config.js 公共配置中的基础配置
all/build/common/webpack.dev.config.js 公共配置中的开发环境配置
all/build/common/webpack.prod.config.js 公共配置中的生产环境配置
app1/build/webpack.config.js 应用系统中的配置

1.all/build/common/webpack.common.config.js

公共配置中的基础配置,先上代码:

const wepackMerge = require('webpack-merge');const Path = require('path');const HtmlWebpackPlugin = require('html-webpack-plugin');const Webpack = require('webpack');const ExtractTextPlugin = require('extract-text-webpack-plugin');const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');const CopyWebpackPlugin = require('copy-webpack-plugin');const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');const ProdConfig = require('./webpack.prod.config');const DevConfig = require('./webpack.dev.config');//根据条件处理相关配置const genarateConfig = (env, dirname, options) => {    //样式loader    let cssLoader = [{        loader: 'css-loader',        options: {            sourceMap: true        }    }, {        loader: 'postcss-loader',        options: {            ident: 'postcss',            plugins: [                require('postcss-cssnext')()            ],            sourceMap: true        }    }, {        loader: 'less-loader',        options: {            sourceMap: true        }    }];    let styleLoader = [{        test: /\.(css|less)$/,        // exclude: /(node_modules|bower_components)/,        use: env === 'prod' ? ExtractTextPlugin.extract({            fallback: 'style-loader',            use: cssLoader        }) : [{            loader: 'style-loader',            options: {                sourceMap: true            }        }].concat(cssLoader)    }];    //脚本loader    let jsLoader = [{        test: /\.js$/,        exclude: /(node_modules|bower_components|(\.exec\.js))/,        use: [{            loader: 'babel-loader'        }].concat(env === 'dev' ? [{            loader: 'eslint-loader'        }] : [])    }, {        test: /\.exec\.js$/,        exclude: /(node_modules|bower_components)/,        use: {            loader: 'script-loader'        }    }];    //文件处理loader    let fileLoaderOptions = {        useRelativePath: false,        name: '[name]-[hash:5].[ext]',        publicPath: '../'    };    if (env === 'prod') {        fileLoaderOptions.limit = 8000;    }    let fileLoader = [{        test: /\.(pdf)$/,        exclude: /(node_modules|bower_components)/,        use: [{            loader: 'file-loader',            options: env === 'dev' ? fileLoaderOptions : Object.assign({}, fileLoaderOptions, {                outputPath: '../dist/pdf',                publicPath: './pdf'            })        }]    }, {        test: /\.(jpg|jpeg|png|icon|gif)$/,        exclude: /(node_modules|bower_components)/,        use: [{            loader: env === 'dev' ? 'file-loader' : 'url-loader',            options: env === 'dev' ? fileLoaderOptions : Object.assign({}, fileLoaderOptions, {                outputPath: '../dist/img',                publicPath: './img'            })        }]    }, {        //解析字体文件        test: /\.(eot|svg|ttf|woff2?)$/,        exclude: /(node_modules|bower_components)/,        use: [{            loader: env === 'dev' ? 'file-loader' : 'url-loader',            options: env === 'dev' ? fileLoaderOptions : Object.assign({}, fileLoaderOptions, {                outputPath: '../dist/fonts',                publicPath: './fonts'            })        }]    }, {        //解析主页面和页面上的图片        test: /\.(html)$/,        exclude: /(node_modules|bower_components)/,        use: {            loader: 'html-loader',            options: {                attrs: ['img:src', 'img:data-src'],                minimize: true            }        }    }];    //webpack插件    let plugins = [];    //HtmlWebpackPlugin 插件    let htmlWebpacks = [new HtmlWebpackPlugin({        template: Path.join(dirname, '../index.ejs'),        inject: true,        filename: 'index.html',        chunks: ['index', 'loader'],        chunksSortMode: function (item1, item2) {            //先加载loader            if (item1.id === 'loader') {                return -1;            } else {                return 1;            }        }    })];    options.form === true && htmlWebpacks.push(new HtmlWebpackPlugin({        template: Path.join(dirname, '../forms/index.ejs'),        inject: true,        filename: 'forms/index.html',        chunks: ['form', 'formLoader'],        chunksSortMode: function (item1, item2) {            //先加载loader            if (item1.id === 'formLoader') {                return -1;            } else {                return 1;            }        }    }));    htmlWebpacks = options.htmlWebpackPlugins || htmlWebpacks;    plugins = plugins.concat(htmlWebpacks);    //复制资源    let copyPlugins = [        new CopyWebpackPlugin([{            from: './views',            to: 'views/'        }, {            from: './test',            to: 'test/'        }], {            ignore: ['**/.svn/**']        })    ];    options.form === true && copyPlugins.push(new CopyWebpackPlugin([{        from: './forms/views',        to: 'forms/views'    }], {        ignore: ['**/.svn/**']    }));    copyPlugins = options.copyPlugins || copyPlugins;    plugins = plugins.concat(copyPlugins);    //全局变量定义    plugins.push(new Webpack.DefinePlugin({        WEBPACK_DEBUG: env === 'dev'    }));    //友好提示插件    plugins.push(new FriendlyErrorsPlugin());    //不打包默认加载项    plugins.push(new Webpack.IgnorePlugin(/^\.\/locale$/, /moment$/));    let entry = {        loader: './loader.js',        index: './index.js'    };    options.form === true && (entry.form = './forms/index.js', entry.formLoader = './forms/loader.js');    entry = options.entry == null ? entry : options.entry;    let config = {        devtool: 'source-map',        context: Path.join(dirname, '../'),        entry: entry,        output: {            path: Path.join(dirname, '../dist/'),            filename: env === 'dev' ? '[name]-[hash:5].bundle.js' : '[name]-[chunkhash:5].bundle.js'        },        module: {            rules: [].concat(styleLoader).concat(jsLoader).concat(fileLoader)        },        plugins: plugins    };    return config;};module.exports = (env, dirname, options) => {    options = options == null ? {} : options;    var config = env === 'dev' ? DevConfig(dirname, options) : ProdConfig(dirname, options);    return wepackMerge(genarateConfig(env, dirname, options), config);};

这个文件也是我们最主要的配置内容,其中大部分内容和之前的框架配置内容一致,这里不做赘述。

这里有区别的就是,我们在输出的函数中,新增了一个 options 参数,这个参数就是用来传递不同应用系统的定制化配置的。

其中:

options.form 是我们特殊应用的一个配置内容,是强业务相关内容,可以略过。

options.htmlWebpackPlugins 是配置 HtmlWebpackPlugin 插件的,由于不同的应用系统的模板配置会有差异,所以我们将其作为配置项传入。

options.copyPlugins 是配置 CopyWebpackPlugin 插件的,不同的应用系统需要复制的内容不同。

options.entry 是配置插件入口的,不同应用系统入口不同。

这里,是我们的业务需求导致会有这些配置,在大家各自的业务中,这块的配置可能都不一样。

2.all/build/common/webpack.dev.config.js

公共配置中的开发环境配置,先上代码:

const Webpack = require('webpack');module.exports = (dirname, options) => {    let gtUIPath = options.gtUIPath;    return {        devServer: {            port: '9090',            overlay: true,            //设置为false则会在页面中显示当前webpack的状态            inline: true,            historyApiFallback: true,            //代理配置            proxy: {                '/gt-ui': {                    target: gtUIPath,                    changeOrigin: true,                    logLevel: 'debug',                    headers: {}                }            },            hot: true,            //强制页面不通过刷新页面更新文件            hotOnly: true        },        plugins: [            //模块热更新插件            new Webpack.HotModuleReplacementPlugin(),            //使用HMR时显示模块的相对路径            new Webpack.NamedModulesPlugin()        ]    };};

这块需要注意的就是我们传递了一个 options.gtUIPath地址以作代理之用。这里主要是为了解决字体资源等跨域的问题。

3.all/build/common/webpack.prod.config.js

公共配置中的生产环境配置,先上代码:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');const HtmlWebpackInlineChunkPlugin = require('html-webpack-inline-chunk-plugin');const Webpack = require('webpack');const ExtractTextPlugin = require('extract-text-webpack-plugin');const CleanWebpackPlugin = require('clean-webpack-plugin');const Path = require('path');const FileManagerPlugin = require('filemanager-webpack-plugin');const SvnInfo = require('svn-info').sync('https://218.106.122.66/svn/application/trunk/gm-ui', 'HEAD');module.exports = (dirname, options) => {    let pakageName = Path.basename(Path.join(dirname, '../'));    return {        plugins: [            //混淆代码            new UglifyJsPlugin({                sourceMap: true,                //多线程处理                parallel: true,                //使用缓存                cache: true            }),            //提取css文件            new ExtractTextPlugin({                filename: '[name]-[hash:5].css'            }),            new CleanWebpackPlugin(['dist'], {                root: Path.join(dirname, '../')            }),            new Webpack.NamedChunksPlugin(),            new Webpack.NamedModulesPlugin(),            //版本信息            new Webpack.BannerPlugin({                banner: `SVNVersion: ${SvnInfo.revision}\nDate: ${new Date().toISOString().slice(0, 10)}`,                raw: false,                entryOnly: true,                include: /\.js/g            }),            //压缩文件夹            new FileManagerPlugin({                onEnd: {                    mkdir: [Path.join(dirname, '../package/')],                    archive: [{                        source: Path.join(dirname, '../dist'),                        destination: Path.join(dirname, `../package/${pakageName}.zip`),                        options: {}                    }]                }            })        ]    };};

这里的配置与框架的配置基本一致,里面的插件也都有讲解,这里就不做赘述了。

4.app1/build/webpack.config.js

应用系统中的配置,先上代码:

const Path = require('path');const wepackMerge = require('webpack-merge');const commonConfig = require('../../build/common/webpack.common.config.js');module.exports = env => {    //通用配置    let pConfig = commonConfig(env, __dirname, {        form: true,        //配置开发环境中框架的访问地址        gtUIPath: 'http://localhost:8020/'    });    //基于通用配置的调整配置    let modifyConfig = {        resolve: {            alias: {                mainCtrl: Path.join(__dirname, '../controllers/main-ctrl')            }        }    };    //返回合并后的配置    return wepackMerge(pConfig, modifyConfig);};

由于公共的配置部分已经抽离出去了,所以这块的配置就非常简单了,这也是我们使用这种配置方案最大的优势。

在这里,我们可以通过options参数和直接 merge 相应配置来做配置上的定制化调整。

如何使用配置

在package.json中做如下配置:

{  "scripts":{    "app1-d":"webpack-dev-server --env dev --config ./app1/build/webpack.config.js --open",    "app1-p":"webpack --env prod --config ./app1/build/webpack.config.js",    "app2-d":"webpack-dev-server --env dev --config ./app2/build/webpack.config.js --open",    "app2-p":"webpack --env prod --config ./app2/build/webpack.config.js"  }}

这样,我们运行对应命令即可。

以上,就是我关于webpack实战中的完整配置方案,希望对大家有所帮助,也希望大家多多提出宝贵意见。

欢迎关注我的微信公众号:

转载于:https://my.oschina.net/lsjcoder/blog/1834190

你可能感兴趣的文章