Vue項目改造拋棄vue-cli配置,重擼webpack4和babel7配置

拋棄自帶的vue.config.js的配置模式,手動使用webpack4進行構建:javascript

webpack4

webpack4 相關loaders和pluginscss

>>>>>>>>>>>>>>>>>>>>>>>相關loader<<<<<<<<<<<<<<<<<<<<<< vue-loader 編譯.vue文件 babel-loader 編譯成ES5 file-loader 解決文件中 import/require() 的資源,轉化爲URL,再輸出到指定文件夾內 url-loader 把圖片轉化成 base64 URLs, 能夠根據limit大小自由控制 css-loader css-loader 解釋 @import and url() 好比 import/require() 而後解析他們 file-loader file-loader 解析文件中的 import/require() 成一個URL 而後輸出到輸出文件中 vue-style-loader style-loader dev環境,把css注入到DOM >>>>>>>>>>>>>>>>>>>>>>>相關plugin<<<<<<<<<<<<<<<<<<<<<< mini-css-extract-plugin 提取css到單獨的文件 clean-webpack-plugin 清理構建的資源 webpack-build-notifier 構建完成桌面提醒 html-webpack-plugin 生成html入口模板 optimize-css-assets-webpack-plugin css去重壓縮 purgecss-webpack-plugin 去除css中未使用的代碼 webpack-dev-server 本地server webpack-spritesmith 自動整合成雪碧圖 compression-webpack-plugin @gfx/zopfli 壓縮代碼,根據算法生成gzip webpack-bundle-analyzer 生成bundle後分析報告,方便優化 複製代碼

安裝依賴html

yarn add -D webpack webpack-cli webpack-dev-server vue-loader babel-loader file-loader css-loader style-loader url-loader mini-css-extract-plugin  clean-webpack-plugin webpack-build-notifier html-webpack-plugin optimize-css-assets-webpack-plugin purgecss-webpack-plugin webpack-spritesmith compression-webpack-plugin webpack-bundle-analyzer
複製代碼

babel 7

@babel/core
@babel/preset-env
@babel/cli
@babel/polyfill
// runtime
@babel/runtime
@babel/plugin-transform-runtime
// 動態插入
@babel/plugin-syntax-dynamic-import
// 支持 ...spread
@babel/plugin-syntax-object-rest-spread
// commonjs
@babel/plugin-transform-modules-commonjs
// 支持 vue jsx語法
@babel/plugin-syntax-jsx
babel-plugin-transform-vue-jsx

//支持 element-ui 按需加載
babel-plugin-component

//支持 lodash 按需加載
babel-plugin-lodash

// 移除 console.log
babel-plugin-transform-remove-console

複製代碼

babel.config.jsvue

const removeConsolePlugin = [];

if (process.env.NODE_ENV === 'production') {
    removeConsolePlugin.push('transform-remove-console');
}

module.exports = {
    // presets: ['@vue/app'],
    presets: [
        [
            '@babel/preset-env',
            {
                // transform any
                loose: true
            }
        ]
    ],
    // 藉助 babel-plugin-component,咱們能夠只引入須要的組件,以達到減少項目體積的目的
    plugins: [
        // import
        '@babel/plugin-syntax-dynamic-import',
        // transform
        '@babel/plugin-transform-runtime',
        '@babel/plugin-transform-modules-commonjs',
        // vue jsx語法
        '@babel/plugin-syntax-jsx',
		'transform-vue-jsx',
		'lodash',
        // spread ...
        // '@babel/plugin-syntax-object-rest-spread',
        [
            'component',
            {
                libraryName: 'element-ui',
                styleLibraryName: 'theme-chalk'
            }
        ],
        ...removeConsolePlugin
    ]
};

複製代碼

webpack.config.jsjava

/** * webpack 4 config * @author master2011zhao@gmail.com * @Date 20190910 */
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// webpack4 使用 mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// extract 被廢棄
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
// clean project
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 壓縮css
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
// notifier
const WebpackBuildNotifierPlugin = require('webpack-build-notifier');
// 壓縮代碼
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const zopfli = require('@gfx/zopfli');
// vue loader
const VueLoaderPlugin = require('vue-loader/lib/plugin');
// 圖片整合成雪碧圖
const SpritesmithPlugin = require('webpack-spritesmith');
// bundle分析
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

// path function
const resolve = src => {
    return path.resolve(__dirname, src);
};

// nginx 配置二級目錄 base url
let serverBaseUrl = '';

// customerTemplate
const templateFunction = function(data) {
    // console.log('---', data)
    const shared = `.sprite_ico { background-image: url(I);display:inline-block;background-size: Wpx Hpx;}`
        .replace('I', data.sprites[0].image)
        .replace('W', data.spritesheet.width)
        .replace('H', data.spritesheet.height);

    const perSprite = data.sprites
        .map(function(sprite) {
            return `.sprite_ico_N { width: Wpx; height: Hpx; background-position: Xpx Ypx;}`
                .replace('N', sprite.name)
                .replace('W', sprite.width)
                .replace('H', sprite.height)
                .replace('X', sprite.offset_x)
                .replace('Y', sprite.offset_y);
        })
        .join('\n');

    return '//out:false' + '\n' + shared + '\n' + perSprite;
};

module.exports = (env, argv) => {
    const isProduction = argv.mode === 'production';

    console.log('isProduction', isProduction);

    // 傳遞給 babel.config.js
    process.env.NODE_ENV = argv.mode;

    // console.log(process.env.NODE_ENV);

    let plugins = [new VueLoaderPlugin()];

    // 生成模板
    let HtmlTemplates = [];

    // 生產環境
    if (isProduction) {
        // 清理項目, 清理不乾淨,須要使用 rm.sh
        plugins.push(
            new CleanWebpackPlugin({
                dry: false,
                verbose: true
            })
        );

        // 雪碧圖
        plugins.push(
            new SpritesmithPlugin({
                src: {
                    //下面的路徑,根據本身的實際路徑配置
                    cwd: path.resolve(__dirname, 'src/assets/icons'),
                    glob: '*.png'
                },
                // 輸出雪碧圖文件及樣式文件
                target: {
                    //下面的路徑,根據本身的實際路徑配置
                    image: path.resolve(__dirname, 'src/assets/sprite.png'),
                    css: [
                        [
                            path.resolve(__dirname, 'src/less/sprite.less'),
                            {
                                format: 'function_based_template'
                            }
                        ]
                    ]
                    // css: path.resolve(__dirname, './src/less/sprite.less')
                },
                // 自定義模板
                customTemplates: {
                    function_based_template: templateFunction
                },
                // 樣式文件中調用雪碧圖地址寫法
                apiOptions: {
                    // 這個路徑根據本身頁面配置
                    cssImageRef: '../assets/sprite.png'
                },
                spritesmithOptions: {
                    // algorithm: 'top-down'
                    padding: 5
                }
            })
        );

        // 構建完成提醒
        plugins.push(
            new WebpackBuildNotifierPlugin({
                title: 'project build',
                suppressSuccess: true,
                suppressWarning: true,
                messageFormatter: function() {
                    return 'build completely';
                }
            })
        );

        // 分離css
        // plugins.push(new ExtractTextPlugin('css/[name].[hash:8].css'));
        plugins.push(
            new MiniCssExtractPlugin({
                // Options similar to the same options in webpackOptions.output
                // all options are optional
                filename: 'css/[name].[hash:8].css',
                chunkFilename: 'css/[name].[hash:8].css',
                publicPath: './' + serverBaseUrl,
                ignoreOrder: false // Enable to remove warnings about conflicting order
            })
        );

        // 去除重複的 less, 好比 common
        plugins.push(
            new OptimizeCssAssetsPlugin({
                assetNameRegExp: /\.css$/g,
                cssProcessor: require('cssnano'),
                cssProcessorPluginOptions: {
                    preset: [
                        'default',
                        {
                            discardComments: {
                                removeAll: true
                            }
                        }
                    ]
                },
                canPrint: true
            })
        );

        //再次壓縮代碼
        plugins.push(
            new CompressionWebpackPlugin({
                deleteOriginalAssets: false,
                test: /\.(js|css|html|woff|ttf|png|jpg|jpeg)$/,
                compressionOptions: {
                    numiterations: 15
                },
                threshold: 10240,
                minRatio: 0.8,
                algorithm(input, compressionOptions, callback) {
                    return zopfli.gzip(input, compressionOptions, callback);
                }
            })
        );

        // 公共提取的chunk
        const commonChunks = ['chunk-vendors', 'runtime', 'chunk-commons', 'css-commons'];

        const minify = {
            collapseWhitespace: true,
            removeComments: true,
            removeRedundantAttributes: true,
            removeScriptTypeAttributes: true,
            removeStyleLinkTypeAttributes: true,
            useShortDoctype: true
        };

        // 生成模板
        HtmlTemplates = [
            new HtmlWebpackPlugin({
                title: 'Index',
                template: resolve('public/index.html'),
                filename: 'index.html',
                hash: true,
                minify,
                chunks: [...commonChunks, 'index'],
                favicon: resolve('public/favicon.ico')
            })
        ];

        // 分析生成的包
        plugins.push(
            new BundleAnalyzerPlugin({
                // 生成report.html
                analyzerMode: 'static'
            })
        );
    } else {
        // 生成模板
        HtmlTemplates = [
            new HtmlWebpackPlugin({
                title: 'Index',
                template: resolve('./public/index.html'),
                filename: 'index.html',
                favicon: resolve('public/favicon.ico'),
                chunks: ['index', 'runtime']
            })
        ];
    }

    return {
        entry: {
            index: resolve('src/main.js')
        },
        output: {
            path: resolve('cdn'),
            filename: 'js/[name].[hash:8].js',
            publicPath: isProduction ? './' + serverBaseUrl : ''
        },
        // 本地調試
        devtool: !isProduction ? 'inline-source-map' : '',
        devServer: {
            port: 3000,
            open: true,
            hot: true,
            // 配置 browserHistory 路由,防止刷新就 404
            historyApiFallback: true,
            compress: true,
            contentBase: path.resolve(__dirname, ''),
            noInfo: false,
            overlay: {
                warnings: true,
                errors: true
            },
            proxy: {
                '/api/v1': {
                    target: 'http://192.168.1.100:18080',
                    changeOrigin: true,
                    router: {
                        '/shareIndex': 'http://192.168.1.110:18080',
                    }
                },
            }
        },
        resolve: {
            // 別名
            alias: {
                '@': resolve('src'),
                '@c': resolve('src/components'),
                '@less': resolve('src/less'),
                '@util': resolve('src/utils'),
                '@assets': resolve('src/assets'),
                '@pages': resolve('src/pages')
            },
            // 自動添加後綴
            extensions: ['.vue', '.js', '.less']
        },
        module: {
            rules: [
                {
                    test: /\.vue?$/,
                    use: 'vue-loader'
                },
                {
                    test: /\.js?$/,
                    use: 'babel-loader'
                },
                {
                    test: /\.css?$/,
                    use: [
                        isProduction ? MiniCssExtractPlugin.loader : 'vue-style-loader',
                        {
                            loader: 'css-loader',
                            options: {}
                        }
                    ]
                },
                {
                    test: /\.less$/,
                    use: [
                        isProduction ? MiniCssExtractPlugin.loader : 'vue-style-loader',
                        'css-loader',
                        {
                            loader: 'less-loader',
                            options: {
                                javascriptEnabled: true
                            }
                        }
                    ]
                },
                {
                    test: /\.(png|jpg|svg|gif|ico|woff|ttf)?$/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                // 這裏的options選項參數能夠定義多大的圖片轉換爲base64
                                fallback: 'file-loader',
                                limit: 10 * 1024, // 表示小於10kb的圖片轉爲base64,大於10kb的是路徑
                                outputPath: 'images', //定義輸出的圖片文件夾名字
                                publicPath: '../images', //css中的路徑
                                // name: '[name].[contenthash:8].[ext]'
                                name: '[sha512:contenthash:base64:8].[ext]'
                            }
                        }
                    ]
                }
            ]
        },
        plugins: [...plugins, ...HtmlTemplates],
        optimization: {
            splitChunks: {
                // 靜態資源緩存
                // test, priority and reuseExistingChunk can only be configured on cache group level.
                cacheGroups: {
                    // 提取 node_modules 裏面依賴的代碼
                    vendors: {
                        test: /[\\/]node_modules[\\/]/,
                        name: 'chunk-vendors',
                        chunks: 'all',
                        minSize: 0,
                        minChunks: 2, //2個共享以及以上都提取
                        priority: -10 //優先級
                    },
                    // 提出每一個模塊公共的代碼
                    commons: {
                        name: 'chunk-commons',
                        test: /\.js$/,
                        chunks: 'initial',
                        minChunks: 2, //兩個共享以及以上都提取,
                        minSize: 0,
                        priority: -20, //優先級
                        reuseExistingChunk: true
                    },
                    css: {
                        name: 'css-commons',
                        test: /\.less$/,
                        minChunks: 2,
                        minSize: 0,
                        priority: -30,
                        chunks: 'initial',
                        reuseExistingChunk: true
                    }
                }
            },
            // I pull the Webpack runtime out into its own bundle file so that the
            // contentHash of each subsequent bundle will remain the same as long as the
            // source code of said bundles remain the same.
            runtimeChunk: 'single'
        }
    };
};
複製代碼

package.jsonnode

scripts:{
    "dev": "webpack-dev-server --mode development",
    "build": "webpack --mode production",
}
複製代碼
相關文章
相關標籤/搜索