vue-cli2.0webpack的理解

一,vue cli的演变

在vue cli是2.0的时候,创建的vue项目,项目结构大体如下:

build负责针对不同编译环境,webpack采用哪些配置,摒弃哪些机制相关
config是build编译文件的另外扩展,把需要用到的配置提取出来,让配置更模块化
src就是写代码的地方了
static静态资源文件夹,注意当打包时这个文件夹下的文件都不会被打包
package.json项目所采用的类库与命令都写在这了,阅读代码首先看这个文件了

而在后来的vue cli3.0+之后,官方把webpack内置化了,只是提供了一个vue.config.js的用户自定义入口。相关的配置官方文档很齐全了:配置参考 | Vue CLI (vuejs.org)

本文主要还是讲讲2.0之前的webpack配置的事情。(哈哈,其实我是遇到旧项目了)

二,package.json

先看这个文件,当我们运行npm run dev时,会在根目录执行这句代码:

webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

1,webpack-dev-server

webpack-dev-server是什么呢? 它其实就是一个微服务器,运行它,也就启动了一个 web 服务器,可以方便地从服务器上打开这个 index.html 了。webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,他比传统的http服务对开发更加简单高效,也就是说它是webpack打包编译预览功能的基石。

2,–inline

并且实时编译文件

3,–progress

显示进度条

4,–config build/webpack.dev.conf.js

编译build文件夹下的webpack.dev.conf.js文件

三,开发环境的webpack配置

上面说了这么多,也就是说开发模式dev下的主角是这个文件webpack.dev.conf.js:

'use strict'
// 引入当前目录中的utils工具配置文件
const utils = require('./utils')
// 引入webpack来使用webpack内置插件
const webpack = require('webpack')
// 引入config目录中的index.js配置文件
const config = require('../config')
// 引入webpack-merge插件用来合并webpack配置对象,也就是说可以把webpack配置文件拆分成几个小的模块,然后合并
const merge = require('webpack-merge')
const path = require('path')
// 引入当前目录下的webpack.base.conf.js配置文件,主要配置的是打包各种文件类型的配置
const baseWebpackConfig = require('./webpack.base.conf')
// 有一些本地资源,例如图片和音视频,在打包过程中没有任何模块使用到它们,但我们却想要把它们放在打包后的资源输出目录,就需要用这个插件复制文件
const CopyWebpackPlugin = require('copy-webpack-plugin')
// 下面是一个自动生成html的插件,能够把资源自动加载到html文件中
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 下面这个插件是用来把webpack的错误和日志收集起来,漂亮的展示给用户
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// 帮助你自动获取可用端口的插件
const portfinder = require('portfinder')

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
// 下面是合并配置对象,将这个配置文件特有的配置添加替换到base配置文件中
const devWebpackConfig = merge(baseWebpackConfig, {
    
    
  module: {
    
    
    // 下面是把utils配置中的处理css类似文件的处理方法拿过来,并且生成cssMap文件
    rules: utils.styleLoaders({
    
     sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  },
  // debtool是开发工具选项,用来指定如何生成sourcemap文件,cheap-module-eval-source-map此款soucemap文件性价比最高
  devtool: config.dev.devtool,
  // 这些devServer选项可以 /config/index.js中在中自定义
  devServer: {
    
    
    clientLogLevel: 'warning', // 配置在客户端的日志等级,这会影响到你在浏览器开发者工具控制台里看到的日志内容
    historyApiFallback: {
    
    
      rewrites: [
        {
    
     from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }
      ]
    }, // 任何路由都命中index.html 文件
    hot: true, // 开启热更新
    contentBase: false, // since we use CopyWebpackPlugin.HTTP 服务器的文件根目录。 默认情况下为当前执行目录,通常是项目根目录,所有一般情况下你不必设置它
    compress: true, // 配置是否启用 gzip 压缩
    host: HOST || config.dev.host,
    port: PORT || config.dev.port,
    open: config.dev.autoOpenBrowser, // 用于在 DevServer 启动且第一次构建完时自动用你系统上默认的浏览器去打开要开发的网页
    overlay: config.dev.errorOverlay
      ? {
    
     warnings: false, errors: true }
      : false, // 当出现编译器错误或警告时,在浏览器中显示全屏覆盖(只报错误不报警告)
    publicPath: config.dev.assetsPublicPath, // 项目部署的地址(前面是www.服务器.com)拼接这里的地址,也就是说静态资源从这里找
    proxy: config.dev.proxyTable, // 开发时本地代理配置
    quiet: true, // 启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。
    watchOptions: {
    
    
      poll: config.dev.poll
    }// 使用文件系统(file system)获取文件改动的通知
  },
  plugins: [
    // DefinePlugin内置webpack插件,专门用来定义全局变量的,下面定义一个全局变量 process.env 并且值是如下
    new webpack.DefinePlugin({
    
    
      'process.env': require('../config/dev.env')
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    // 当webpack编译错误的时候,来中断打包进程,防止错误代码打包到文件中,你还不知道
    new webpack.NoEmitOnErrorsPlugin(),
    new HtmlWebpackPlugin({
    
    
      filename: 'index.html',
      template: 'index.html',
      inject: true
    }), // 设置为true表示把所有的js文件都放在body标签的屁股
    // 把static文件下的所有文件,拷贝到指定文件夹
    new CopyWebpackPlugin([
      {
    
    
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ]
})

module.exports = new Promise((resolve, reject) => {
    
    
  // 这部分代码就是实现选用并开启可用的端口
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    
    
    if (err) {
    
    
      reject(err)
    } else {
    
    
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // 这部分代码是编译完成的控制台提示信息
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
    
    
        compilationSuccessInfo: {
    
    
          messages: [`Your application is running here: http://${
      
      devWebpackConfig.devServer.host}:${
      
      port}`]
        },
        onErrors: config.dev.notifyOnErrors
          ? utils.createNotifierCallback()
          : undefined
      }))

      resolve(devWebpackConfig)
    }
  })
})

整个文件都在搞配置,最后promise返回了一个对象devWebpackConfig,这个对象就是webpack.dev.conf.js的核心。

首先说明的是,在开发环境和生产环境,webpack的配置是有很大不同的。比如在开发环境,我们需要快速的开发,所以我们可能需要一些实时加载和热更新等功能。但是在生产环境,我们不需要这些,我们需要更小的bundle,更轻量的source map,以及更轻量的资源,以改善加载时间。因此,为给个环境配置不同的webpack配置是必做的一步。

​ 虽然我们会为环境做区分,但是基于不重复原则,vue-cli为两个环境公用的配置整合到了(build/webpack.base.conf.js)文件中。然后利用webpack-merge插件将配置整合在一起,可以看到:

const devWebpackConfig = merge(baseWebpackConfig, {
    
    
  ……//……这部分代码就是开发环境下的独有配置
 })

为了更大程度的模块化,这里面的一些配置又是定义在config/index.js(开发的是dev,生产的是build)中:

'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require('path')

module.exports = {
    
    
  dev: {
    
    

    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
    
    
      '/api': {
    
    
        target: 'http://42.192.69.90:80', // 外网接口域名
        changeOrigin: true, // 是否启用跨域
        pathRewrite: {
    
    
          '^/api': ''
        }
      }
    },

    // Various Dev Server settings
    host: '0.0.0.0', // can be overwritten by process.env.HOST,写成0.0.0.0是可以监听本机的所有ipv4地址,这样其他电脑访问本机ip可访问本项目
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: false,
    errorOverlay: true,
    notifyOnErrors: true,
    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-

    // Use Eslint Loader?
    // If true, your code will be linted during bundling and
    // linting errors and warnings will be shown in the console.
    useEslint: true,
    // If true, eslint errors and warnings will also be shown in the error overlay
    // in the browser.
    showEslintErrorsInOverlay: false,

    /**
     * Source Maps
     */

    // https://webpack.js.org/configuration/devtool/#development
    devtool: 'cheap-module-eval-source-map',

    // If you have problems debugging vue-files in devtools,
    // set this to false - it *may* help
    // https://vue-loader.vuejs.org/en/options.html#cachebusting
    cacheBusting: true,

    cssSourceMap: true
  },

  build: {
    
    
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: './',

    /**
     * Source Maps
     */

    productionSourceMap: false,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: true,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }
}

四,生产环境的webpack配置

当我们打生产包的时候:

"build": "node build/build.js",

也就是运行这个文件:

在这里插入图片描述

五,开发和生产通用的webpack配置

也就是这个webpack.base.confjs文件:

'use strict'
const path = require('path')
// tils主要用来处理css-loader和vue-style-loader的
const utils = require('./utils')
const config = require('../config')
// vue-loader.conf配置文件是用来解决各种css文件的,定义了诸如css,less,sass之类的和样式有关的loader
const vueLoaderConfig = require('./vue-loader.conf')
// 此函数是用来返回当前目录的平行目录的路径
function resolve (dir) {
    
    
  return path.join(__dirname, '..', dir)
}
// 对.js和.vue文件在编译之前进行检测,检查有没有语法错误
const createLintingRule = () => ({
    
    
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  enforce: 'pre',
  include: [resolve('src'), resolve('test')],
  options: {
    
    
    formatter: require('eslint-friendly-formatter'),
    emitWarning: !config.dev.showEslintErrorsInOverlay
  }
})

module.exports = {
    
    
  context: path.resolve(__dirname, '../'),
  entry: {
    
    
    app: ['babel-polyfill', './src/main.js']
  },
  output: {
    
    
    path: config.build.assetsRoot,
    filename: '[name].js',
    // 上线地址,也就是真正的文件引用路径,如果是production生产环境,是 './'
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    
    
    // resolve是webpack的内置选项,顾名思义,决定要做的事情,也就是说当使用 import "jquery",该如何去执行这件事
    // 情就是resolve配置项要做的,import jQuery from "./additional/dist/js/jquery" 这样会很麻烦,可以起个别名简化操作
    extensions: ['.js', '.vue', '.json'], // 省略扩展名,也就是说.js,.vue,.json文件导入可以省略后缀名,这会覆盖默认的配置,所以要省略扩展名在这里一定要写上
    alias: {
    
    
      // 后面的$符号指精确匹配,也就是说只能使用 import vuejs from "vue" 这样的方式导入vue.esm.js文件,不能在后面跟上 vue/vue.js
      'vue$': 'vue/dist/vue.esm.js',
      // resolve('src') 其实在这里就是项目根目录中的src目录,使用 import somejs from "@/some.js" 就可以导入指定文件
      '@': resolve('src')
    }
  },
  module: {
    
    
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      // 对vue文件使用vue-loader,该loader是vue单文件组件的实现核心,专门用来解析.vue文件的
      {
    
    
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      // 对js文件使用babel-loader转码,该插件是用来解析es6等代码
      {
    
    
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      // 对图片相关的文件使用 url-loader 插件,这个插件的作用是将一个足够小的文件生成一个64位的DataURL
      {
    
    
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
    
    
          limit: 1,
          name: utils.assetsPath('image/[name].[hash:7].[ext]')
        }
      },
      // 对视频文件的处理
      {
    
    
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
    
    
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      // 对字体文件的处理
      {
    
    
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
    
    
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  node: {
    
    
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native).
    setImmediate: false,
    // prevent webpack from injecting mocks to Node native modules
    // that does not make sense for the client
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}

猜你喜欢

转载自blog.csdn.net/weixin_42349568/article/details/120723252