webpack 打包vue项目

194 阅读2分钟

安装webpack4

yarn add webpack@4.41.6 webpack-cli@3.3.11 --dev 指定webpack4

配置文件

  • webpack.commom.js存放公共的配置
  • webpack.dev是开发独有的配置
  • prod是线上独有的配置

loader

处理less, 压缩提取css

less(less less-loader css-loader)-> 压缩提取css(mini-css-extract-plugin) css 预处理 postcss-loader

yarn add less less-loader css-loader mini-css-extract-plugin postcss-loader postcss-preset-env --dev

webpack.common.js

entry: './src/main.js',
  output: {
    filename: 'js/main.js',
    path: path.resolve('dist')  // 输出文件路径, 必须使用绝对路径
  },
  module: {
    rules: [
      {
        test: /\.less$/, // 处理less文件
        use: [ // loader处理的顺序是从下到上
          // 'style-loader' // 生成一个 style 标签,将 css-loader 处理后的字符串加载到界面中
          MiniCssExtractPlugin.loader, // 将CSS提取到CSS文件中
          'css-loader', // 将 css 代码处理为符合 commonjs 规范的代码,处理完成之后的内容是字符串
          'less-loader' // 将 less 语法处理成 css 语法
        ]
      },
      {
        test: /\.css/,
        use: [
          MiniCssExtractPlugin.loader, // 将CSS提取到CSS文件中
          'css-loader', // 将 css 代码处理为符合 commonjs 规范的代码,处理完成之后的内容是字符串
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  // 下面的代码就好比是将我们当前配置中环境需要用到的 css处理语法加载进来
                  ['postcss-preset-env']
                ]
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/build.css' // 提取css文件中
    })
  ]

在package.json 文件的scripts 添加命令

"build:dev": "webpack --config webpack.common.js --mode development"

babel-loader

处理 JS babel-loader @babel/core 、@babel/preset-env 、 eslint-loader

yarn add babel-loader @babel/core @babel/preset-env babel-eslint --dev

webpack.common.js

{
        test: /\.js$/, // js 处理(打包、校验、兼容、压缩)
        loader: 'babel-loader',
        exclude: /node_modules/, //node_modules 文件夹下的文件不处理
        options: {
          presets: [ // 预设 只是一个平台, 本身不处理
            [
              '@babel/preset-env', // 这个预设置只帮助我们完成一些基本的兼容 ,
              {
                useBuiltIns: 'usage', // usage 会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加。
                corejs: { version: 3 },
                targets: { // 浏览器版本
                  chrome: '60',
                  firefox: '60', 
                  ie: "9", 
                  safari: '10', 
                  edge: '17'
                }
              }
            ]
          ]
        }
      }

eslint-loader

yarn add eslint eslint-loader --dev

webpack.common.js

 {
        test: /\.js$/,  // js 处理(校验)
        enforce: 'pre', // loader 先执行
        exclude: /node_modules/,
        loader: 'eslint-loader',
        options: {
          fix: true // 解决问题的代码
        }
 }

处理字体等

处理图片

yarn add file-loader url-loader --dev

webpack.common.js

{ // 处理图片
        test: /\.(png|gif|jpg)$/, // 处理图片
        loader: 'url-loader',
        options: {
          esModule: false,
          limit: 2 * 1024,
          outputPath: 'img'
        }
      },

vue-loader

yarn add vue-template-compiler vue-loader eslint-plugin-vue --dev

webpack.common.js

const VueLoaderPlugin = require('vue-loader/lib/plugin')
{
        test: /\.vue$/,
        exclude: /node_modules/,
        loader: 'vue-loader'
      }
new VueLoaderPlugin() // 配合vue-loader

处理生成html

yarn add html-webpack-plugin --dev

webpack.common.js

new HtmlWebpackPlugin({
      template: './public/index.html',
      publicPath: './', // 公共路径
    }),

清理打包历史文件夹

yarn add clean-webpack-plugin --dev
new CleanWebpackPlugin(),

拷贝静态文件

yarn add copy-webpack-plugin --dev

webpack.common.js

new CopyWebpackPlgin({
      patterns: [
        { from: 'src/assets/', to: './assets'},
        'public'
      ]
    })

开发配置:webpack.dev.js

服务器

yarn add webpack-dev-server --dev
"serve": "webpack-dev-server --open --config webpack.dev.js"

webpack.dev.js

const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')
const webpack = require('webapack')
const path = require('path')
// 合并公共配置
module.exports = merge(commonConfig, { 
  mode: 'development', // 开发模式
  devtool: 'cheap-module-eval-source-map', // 调试
  devServer: {
    clientLogLevel: 'warning', // 日历级别
    hot: true, //  HMR
    open: true, // 打开浏览器
    contentBase: [path.join(__dirname, './dist'), 'public', path.join(__dirname, 'src/assets/')], // 获取静态资源
    publicPath: '/',
    compress: true, // 一切服务都启用gzip 压缩:
    port: 9000
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin() // HMR
  ]
})

线上 webpack.prod.js

const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.common')
const CopyWebpackPlgin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 压缩CSS
// 合并公共配置
module.exports = merge(commonConfig, { 
  mode: 'production', // 开发模式
  devtool: 'none', //没有源码
  optimization: { // 优化
    // useExports: true, // 没有使用的不会导出
    minimize: true, // 压缩html
    minimizer: [ 
      new OptimizeCSSAssetsPlugin({}) // 压缩CSS
    ]
  },
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10*1024,
            esModule: false,
            name: 'img/[name].[hash:8].[ext]'
          }
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: 'fonts/[name].[hash:8].[ext]'
          }
        }
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlgin({
      patterns: [
        { from: 'src/assets/', to: './assets'},
        'public'
      ]
    })
  ]
})

整理webpack.common.js

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 插件 提取CSS, 压缩
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  // mode: 'development',
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),  // 输出文件路径, 必须使用绝对路径
    filename: '[name][hash:8].js',  // hash
  },
  // 配置通过别名来吧原导入路径映射成一个新的导入路径
  resolve: {
    // 导入语句没有携带文件后缀时, webpack会自动带上后缀后尝试访问文件是否存在
    extensions: ['.js', '.vue', 'json'], //用于配置在尝试过程中用到的后缀列表
    alias: { // 别名
      components: path.join(__dirname, 'src/components') 
    }
  },
  module: {
    rules: [
      {
        test: /\.less$/, // 处理less文件
        use: [ // loader处理的顺序是从下到上
          // 'style-loader' // 生成一个 style 标签,将 css-loader 处理后的字符串加载到界面中
          MiniCssExtractPlugin.loader, // 将CSS提取到CSS文件中
          'css-loader', // 将 css 代码处理为符合 commonjs 规范的代码,处理完成之后的内容是字符串
          'less-loader' // 将 less 语法处理成 css 语法
        ]
      },
      {
        test: /\.css/,
        use: [
          MiniCssExtractPlugin.loader, // 将CSS提取到CSS文件中
          'css-loader', // 将 css 代码处理为符合 commonjs 规范的代码,处理完成之后的内容是字符串
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  // 下面的代码就好比是将我们当前配置中环境需要用到的 css处理语法加载进来
                  ['postcss-preset-env']
                ]
              }
            }
          }
        ]
      },
      {
        test: /\.js$/, // js 处理(打包、校验、兼容、压缩)
        loader: 'babel-loader',
        exclude: /node_modules/, //node_modules 文件夹下的文件不处理
        options: {
          presets: [ // 预设 只是一个平台, 本身不处理
            [
              '@babel/preset-env', // 这个预设置只帮助我们完成一些基本的兼容 ,
              {
                useBuiltIns: 'usage', // usage 会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加。
                corejs: { version: 3 },
                targets: { // 浏览器版本
                  chrome: '60',
                  firefox: '60', 
                  ie: "9", 
                  safari: '10', 
                  edge: '17'
                }
              }
            ]
          ]
        }
      },
      {
        test: /\.(vue|js)$/,  // js 处理(校验)
        enforce: 'pre', // loader 先执行
        exclude: /node_modules/,
        loader: 'eslint-loader',
        options: {
          fix: true // 解决问题的代码
        }
      },
      { // 处理字体
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10000
          }
        }
      },
      { // 处理图片
        test: /\.(png|gif|jpg)$/, // 处理图片
        loader: 'url-loader',
        options: {
          esModule: false,
          limit: 2 * 1024,
          outputPath: 'img'
        }
      },
      {
        test: /\.vue$/,
        exclude: /node_modules/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[hash:8].css', // 提取css文件中
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
      publicPath: './', // 公共路径
    }),
  ]
}