webpack4配置vue开发环境

本文总结Webpack4常见的配置。
1、基础配置(让项目跑起来)
2、webpack处理css
3、webpack处理sass文件
4、webpack为sass添加source map
5、webpack为css添加CSS3前缀
6、抽离样式表为单独的css文件并打版本号
7、webpack压缩CSS
8、webpack压缩js
9、webpack添加页面模板
10、webpack清理打包后的dist目录
11、webpack处理图片
12、webpack压缩图片
13、webpack把小图片转为base64
14、webpack处理文字
15、webpack配置js使用sourceMap
16、webpack开启热更新和代理配置
17、webpack启用babel转码
18、alias对文件路径优化
19、使用happypack并发执行任务
案例中自带不细说:
1、定义全局变量
2、合并提取webpack公共配置
3、使用静态资源路径publicPath(CDN)

1、基础配置

让项目跑起来
项目初始化:
npm init
安装webpack、vue、与vue-loader:
npm i webpack vue vue-loader -D
webpack4 已经启用webpack-cli :
npm i webpack-cli -s -d
解析.vue文件,与内联css:
npm i css-loader vue-template-compiler -D
并按照下面目录构建项目

image.png

app.vue

<template>
    <div> luckfine </div>
</template>
<script>
    export default {
        data () {
            //text: 'luckfine'
        }
    }
</script>
<style>
</style>

index.js

// index.js
import Vue from 'vue'
import App from '../components/app.vue'

const root = document.createElement('div')
document.body.appendChild(root)

new Vue({
    render: (h) => h(App)
}).$mount(root)

webpack.js

// webpack.js
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    entry:  path.join(__dirname, 'src/spa/index.js'),
    mode:'develop',
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: 'vue-loader'
            }
        ]
    },
    plugins:[
        new VueLoaderPlugin()
    ],
}

在package.json 文件里的scripts对象里面添加一个脚本:
(注意:webpack4中已经在启动时用mode指定启动环境)

 "scripts": {
    "build": "webpack --config webpack.config.js --mode=development"
  },
image.png

让我们的spa项目先跑起来

npm install webpack-dev-server -s -d
npm install html-webpack-plugin -d -s
// webpack.config.js

const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry:  path.join(__dirname, 'src/h5/pages/demo.js'),
    mode:'develop',
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: 'vue-loader'
            }
        ]
    },
    resolve: {
        extensions: [
          '.vue', '.js'
        ],
        modules: ["node_modules"],
        alias: {
          vue: 'vue/dist/vue.min.js',
          components: path.resolve(__dirname + '/src/components/'),
          '@': path.resolve('src')
        }
    },
    plugins:[
        new HtmlWebpackPlugin(),
        new VueLoaderPlugin()
    ],
    devServer: {
        historyApiFallback: {
          index: `/dist/h5/index.html`
        },
        host: '0.0.0.0',
        disableHostCheck: true
    }
}

添加项目快捷启动

"dev": "webpack-dev-server --inline --hot --mode=development",

npm run dev

image.png

项目已经跑起来了,开始webpack的配置

2、webpack处理css

npm i -D css-loader style-loader

//  webpack.config.js
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css/,
                use: ['style-loader', 'css-loader'] // use的顺序从右往左
            }
        ]
    },
image.png

3、webpack处理sass文件

npm install sass-loader node-sass -D

    module: {
        rules: [
            {
                test: /.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.(sc|sa|c)ss$/,
                use: ['style-loader', 'css-loader', 'sass-loader'] // use的顺序从右往左
            }
        ]
    },
image.png

4、webpack为sass添加source map

image.png
            {
                test: /\.(sc|sa|c)ss$/,
                use: [
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }

添加后


image.png

5、webpack为css添加CSS3前缀

npm i -D postcss-loader autoprefixer postcss 

在刚才的index.css 加上display: flex;
根目录新建一个postcss.config.js

module.exports = {
  plugins: [
    require('precss'),
    require('autoprefixer')
  ]
}
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.(sc|sa|c)ss$/,
                use: [
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'postcss-loader'
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }
        ]
    },
image.png

6、抽离样式表为单独的css文件并打版本号

npm install webpack-merge -s -d
npm i -D mini-css-extract-plugin
//webpack.prod.config.js
const merge = require('webpack-merge')
const webpack = require('webpack');
const baseConfig = require('./webpack.config.js')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devMode = process.env.NODE_ENV !== 'production'


module.exports = merge(baseConfig, {
    module: {
        rules: [
            {
                test: /\.(sc|sa|c)ss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'postcss-loader'
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: devMode ? '[name].css' : '[name].[hash:8].css', 
            chunkFilename: devMode ? '[id].css': '[id].[hash:8].css'
        })
    ]
})

"dist": "webpack --config webpack.prod.config.js --mode=production",

image.png

7、webpack压缩CSS

npm i -D optimize-css-assets-webpack-plugin
    optimization: {
        minimizer: [
            // 压缩CSS
            new OptimizeCSSAssertsPlugin({})
        ]
    },
image.png

8、webpack压缩js

npm i -D uglifyjs-webpack-plugin
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

    optimization: {
        minimizer: [
            // 压缩CSS
            new OptimizeCSSAssertsPlugin({}),
            // 压缩JS
            new UglifyJsPlugin({
                // 有很多可以配置
                cache: true,
                parallel: true,
                sourceMap: true,
                uglifyOptions: {
                     // 在UglifyJs删除没有用到的代码时不输出警告
                    warnings: false,
                    output: {
                        // 删除所有的注释
                        comments: false,
                        // 最紧凑的输出
                        beautify: false
                    },
                    compress: {
                        // 删除所有的 `console` 语句
                        // 还可以兼容ie浏览器
                        drop_console: true,
                        // 内嵌定义了但是只用到一次的变量
                        collapse_vars: true,
                        // 提取出出现多次但是没有定义成变量去引用的静态值
                        reduce_vars: true,
                    }
                }
            })
        ]
    },
image.png

Uglify-js不支持es6语法,请使用terser插件, 于是我们更改使用terser插件试试, 其实你继续用uglifyjs-webpack-plugin也可以, 只需要配合babel先转下。

const TerserPlugin = require('terser-webpack-plugin');
    optimization: {
        minimizer: [
            // 压缩CSS
            new OptimizeCSSAssertsPlugin({}),
            // 压缩JS
            new TerserPlugin({
                cache: true,
                parallel: true,
                sourceMap: true
            })
        ]
    },

更多配置见官网terser-webpack-plugin

image.png

9、webpack添加页面模板

html-webpack-plugin插件可以把js/css注入到一个模板文件, 所以不需要再手动更改引用。
创建一个模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    <meta name="format-detection" content="telephone=no">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
    
</body>
</html>
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

plugins: [
    // 打包模板
        new HtmlWebpackPlugin({
            inject: true,
            hash: true,
            cache: true,
            chunksSortMode: 'none',
            title: '页面模板', // 可以由外面传入
            filename: 'index.html', // 默认index.html
            template: 'src/spa/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true,
                removeRedundantAttributes: true,
                removeScriptTypeAttributes: true,
                removeStyleLinkTypeAttributes: true
            }
        }),
],

image.png

10、webpack清理打包后的dist目录

npm i -D clean-webpack-plugin

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

plugins:[
        new CleanWebpackPlugin()
]

11、webpack处理图片

            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            limit: 1,
                            name: '[name].[hash].[ext]'
                        },
                    },
                ]
            }
image.png

12、webpack压缩图片

npm i -D image-webpack-loader

            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            limit: 1,
                            name: '[name].[hash].[ext]'
                        },
                    },
                    {
                        loader: 'image-webpack-loader',
                        options: {
                          mozjpeg: {
                            progressive: true,
                            quality: 65
                          },
                          // optipng.enabled: false will disable optipng
                          optipng: {
                            enabled: false,
                          },
                          pngquant: {
                            quality: '65-90',
                            speed: 4
                          },
                          gifsicle: {
                            interlaced: false,
                          },
                          // the webp option will enable WEBP
                          webp: {
                            quality: 75
                          }
                        }
                    }
                ]
            }

目前图片112kb,压缩后31kb

13、webpack把图片转为base64

npm i -D url-loader

            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            // 具体配置见插件官网
                            limit: 10000,
                            name: '[name]-[hash:5].[ext]'
                        },
                    },
                    {
                        loader: 'image-webpack-loader',
                        options: {
                          mozjpeg: {
                            progressive: true,
                            quality: 65
                          },
                          // optipng.enabled: false will disable optipng
                          optipng: {
                            enabled: false,
                          },
                          pngquant: {
                            quality: '65-90',
                            speed: 4
                          },
                          gifsicle: {
                            interlaced: false,
                          },
                          // the webp option will enable WEBP
                          webp: {
                            quality: 75
                          }
                        }
                    }
                ]
            },
image.png

14、webpack处理文字

{
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    options: {
        // 文件大小小于limit参数,url-loader将会把文件转为DataUR
        limit: 10000,
        name: '[name]-[hash:5].[ext]',
        output: 'fonts/'
    }
},

15、webpack配置js使用sourceMap

devtool: 'inline-source-map'

16、webpack开启热更新和代理配置

    devServer: {
        clientLogLevel: 'warning', // 输出日志级别
        hot: true, // 启用热更新
        contentBase: path.resolve(__dirname, 'dist'), // 告诉服务器从哪里提供内容
        publicPath: '/', // 此路径下的打包文件可在浏览器下访问
        compress: true, // 启用gzip压缩
        // publicPath: './',
        disableHostCheck: true,
        host: '0.0.0.0',
        port: 8080,
        open: true, // 自动打开浏览器
        overlay: { // 出现错误或者警告时候是否覆盖页面线上错误信息
            warnings: true,
            errors: true
        },
        quiet: true,
        watchOptions: { // 监控文件相关配置
            poll: true,
            ignored: /node_modules/, // 忽略监控的文件夹, 正则
            aggregateTimeout: 300, // 默认值, 当你连续改动时候, webpack可以设置构建延迟时间(防抖)
        }
    },

webpack启用babel转码
npm i -D babel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime

// 编译js
{
    test: /\.js$/,
    exclude: /(node_modules|bower_components)/,
    use: {
        loader: 'babel-loader?cacheDirectory', // 通过cacheDirectory选项开启支持缓存
        options: {
          presets: ['@babel/preset-env']
        }
    }
},

添加.babelrc文件


// 仅供参考
{
    "presets": [
      [
        "@babel/preset-env"
      ]
    ],
    "plugins": [
      [
        "@babel/plugin-transform-runtime",
        {
          "corejs": false,
          "helpers": true,
          "regenerator": true,
          "useESModules": false,
          "absoluteRuntime": "@babel/runtime"
        }
      ]
    ]
  }

18、alias对文件路径优化

配置alias方便路径的检索效率。 加快模块的查找速度

   resolve: {
        extensions: ['.vue', '.js'],
        modules: ['node_modules'],
        alias: {
          components: __dirname + '/src/components/',
          assets: __dirname + '/src/assets/'
        }
    },

19、使用happypack并发执行任务

在 Loader 配置中,所有文件的处理都交给了 happypack/loader 去处理,使用紧跟其后的 querystring ?id=babel 去告诉 happypack/loader 去选择哪个 HappyPack 实例去处理文件。


const HappyPack = require('HappyPack')
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

{
    test: /\.js$/,
    exclude: /(node_modules|bower_components)/,
    use: [
        {
            // 一个loader对应一个id
            loader: "happypack/loader?id=luckfine"
        }
    ]
},

 
new HappyPack({
      // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
      id:'luckfine',
        //如何处理  用法和loader 的配置一样
      loaders: [{
        loader: 'babel-loader?cacheDirectory=true',
      }],
      //共享进程池
      threadPool: happyThreadPool,
      //允许 HappyPack 输出日志
      verbose: true,
}),

本文源码:https://github.com/luckFine/vue-webpack.git
可手抖star,欢迎有遗漏补充。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335