webpack4 一点通

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

安装

webpack 最新版本 v4.26.0

github star:45.292k

需要同时安装 webpackwebpack-cliwebpack-dev-server,建议安装在每个独立项目而不是全局,这样方便单独使用 webpack3 或者 webpack4

yarn add webpack webpack-cli webpack-dev-server -D 
或者:
cnpm install webpack webpack-cli webpack-dev-server -D

2018年8月25号webpack4正式发布。再次之后只要使用npm install webpack命令,默认安装的就是版本4

基础版

webpack4 会根据环境自动设置一些默认配置,下面是一个最基础的配置:

package.json

// --config webpack.config.js  配置文件的路径
// --mode=production 用到的模式
// --progress 打印出编译进度的百分比值
"scripts": {
  "dev": "webpack-dev-server --progress --mode=development --config webpack.config.js",
  "build": "webpack --progress --mode=production --config  webpack.config.js",
},

webpack.config.js

const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
    entry: './main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/', // 资源引用路径前后都有斜杠
        filename: '[name].js'
    },
    devServer: {
        open: true, // 自动打开浏览器
        host: '0.0.0.0',
        port: 3003,
    },
    plugins: [
        new HtmlWebpackPlugin({ 
            filename: 'index.html',
            template: path.resolve(__dirname, 'template.html'),
        }),
        new webpack.HotModuleReplacementPlugin(), // 开启webpack热更新功能
        new webpack.NoEmitOnErrorsPlugin(), // webpack编译出错跳过报错阶段,在编译结束后报错
    ],
}

浏览器输入 http://0.0.0.0:3003/webpack-dev-server 可以查看开发环境文件结构

实用版

package.json

在实际使用中建议分开配置,生产环境和开发环境分别对应一个配置文件

// --config config/webpack.dev.js  配置文件的路径
// --progress 打印出编译进度的百分比值
"scripts": {
    "start": "webpack --progress --config config/webpack.dll.js",
    "dev": "webpack-dev-server --progress --config config/webpack.dev.js",
    "build": "webpack --progress --config config/webpack.prod.js"
},

base.conf.js

把公共配置提取到一个公用文件 base.conf.js 中,后期所有修改都在这个文件,其他配置文件不动,减小人为错误

const os = require('os')
const getIp = () => { // 获取本地ip
    var interfaces = os.networkInterfaces();
    for (var devName in interfaces) {
        var iface = interfaces[devName];
        for (var i = 0; i < iface.length; i++) {
            var alias = iface[i];
            if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
                return alias.address;
            }
        }
    }
}

module.exports = {
    base: {
        rootPath: '/',
        fileName: 'dist',
        filePath: 'dist/static',
    },
    dev: {
        useEslint: true,
        host: getIp(),
        port: 3001,
        proxy: [
            {
                context: ['/v2', '/xw', '/wap', '/information'],
                target: 'https://xwm.jindanlicai.com/',
                changeOrigin: true,
                cookieDomainRewrite:{
                    "*":getIp()
                }
            },
        ]
    }
}

webpack.base.js

提取开发环境和取生产环境的相同部分到基础配置文件 webpack.base.js 中

const config = require('./base.conf.js') // 配置文件
const path = require('path') 
const webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const HappyPack = require('happypack') // 多进程 默认三个
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })

// 处理路径
function resolve (dir) { 
    return path.join(__dirname, '..', dir)
}

// eslint检测
const createLintingRule = () => ({ 
    test: /\.(js|vue)$/,
    loader: 'eslint-loader',
    enforce: 'pre',
    exclude: /node_modules/,
    include: [resolve('src')],
    options: {
        formatter: require('eslint-friendly-formatter'),
        emitWarning: true
    }
})

// 获取当前环境
const prod = process.env.NODE_ENV === 'production' 

module.exports = {
    context: path.resolve(__dirname, '../'), // 作用于entry 和 loader
    entry: {
        index: './src/main.js',
    },
    output: { 
        path: resolve(`${config.base.filePath}`), // 输出到static这个地址 只能是绝对路径
        filename: 'js/[name].js',
        chunkFilename: 'js/[name]_[chunkhash:6].js'
    },
    resolve: {
        extensions: ['.css', '.less', '.js', '.vue', '.json'], // 使用的扩展名
        alias: {
            // 'vue$': 'vue/dist/vue.esm.js', // 模块别名列表
            '@': resolve('src'),
        }
    },
    module: {
        // 忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制,忽略部分插件可以提高构建性能
        noParse: /^(vue|vue-router|vuex|vuex-router-sync|axios)$/,
        rules: [
            ...(config.dev.useEslint ? [createLintingRule()] : []),
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                include: resolve('src')
            },
            {
                test: /\.pug$/,
                loader: 'pug-plain-loader',
                include: resolve('src')
            },
            {
                test: /\.css$/,
                oneOf: [
                    // 这里匹配 `