webpack構建技巧之生產篇

本文接前篇 webpack構建技巧之開發篇,但可獨立使用。

項目目錄:

一、入口

入口與開發篇相同

function resolve(dir) {
  return path.join(__dirname, '..', dir) //返回的是項目目錄下的文件夾
} 
module.exports = {
  entry: resolve('src/main.js')
}

二、出口

出口與開發篇有點差別

  output: {
    path: resolve('dist'),
    filename: 'static/js/[name].[hash:8].js',
    chunkFilename: 'static/js/[name].[hash:8].chunk.js',
    publicPath: "./"
  },

關於publicPath:

公共路徑,它會在你所有的路徑前加指定參數。看圖:

這是 publicPath = ' ./ ' 下的文件路徑

這是默認的,也就是 publicPath = ' ' 下的文件路徑:

 

三、module

其他的處理除css外與開發篇相同,以下就僅僅把代碼貼上:

     {
        test: /\.(htm|html)$/i,
        use: [{
          loader: 'html-withimg-loader'
        }]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        include: /\src/,
        use: {
          loader: 'babel-loader',
        }
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: 'static/img/[name].[hash:8].[ext]',
          }
        }]
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'static/media/[name].[ext]'
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'static/fonts/[name].[ext]'
        }
      },

對於css的處理:

我們更多的情況下是會引入外部的css文件,這裏處理的目的就是把多個css文件處理成一個文件並用外聯的方法引入。

首先,提取css,webpack4+用 mini-css-extract-plugin 這個插件,其他使用 extract-text-webpack-plugin 這個插件。

webpack4+:

在前面引入插件

//webpack 4+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

//webpack 4-
const ExtractTextPlugin = require('extract-text-webpack-plugin')

    {    
        test: /\.(css|less)$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../../' //這個publicPath是爲了解決css中引入背景圖的路徑問題
            }
          },
          'css-loader',
          {
            loader: require.resolve('postcss-loader'),
            options: {
              ident: 'postcss',
              plugins: () => [
                require('postcss-flexbugs-fixes'),
                autoprefixer({
                  browsers: [
                    '>1%',
                    'last 4 versions',
                    'Firefox ESR',
                    'not ie < 9',
                  ],
                  flexbox: 'no-2009',
                }),
              ],
            },
          },
          'less-loader'
        ],

      },

webpack4-:

     {
                test: /\.(css|less)$/,
                loader: ExtractTextPlugin.extract(
                    Object.assign({
                        fallback: {
                            loader: require.resolve('style-loader'),
                            options: {
                                hmr: false,
                            },
                        },
                        publicPath:'../../', //接css引入背景圖的路徑問題
                        use: [
                          {
                                loader: require.resolve('css-loader'),
                                options: {
                                    importLoaders: 1,
                                    minimize: true
                                },
                            },
                            {
                                loader: require.resolve('postcss-loader'),
                                options: {
                                    ident: 'postcss',
                                    plugins: () => [
                                        require('postcss-flexbugs-fixes'),
                                        autoprefixer({
                                            browsers: [
                                                '>1%',
                                                'last 4 versions',
                                                'Firefox ESR',
                                                'not ie < 9',
                                            ],
                                            flexbox: 'no-2009',
                                        }),
                                    ],
                                },
                            },
                            {
                                loader: require.resolve('less-loader'),
                            },
                        ],
                    }, )
                ),
            },

然後在plugins中生成css文件:

new MiniCssExtractPlugin({
      filename: 'static/css/[name].[hash:8].css'
    }),
new ExtractTextPlugin({
      filename: 'static/css/[name].[hash:8].css'
    }),

關於publicPath:

假設你在開發中寫如如下背景圖樣式:

顯然這在線上環境中是那不到的,因爲這個路徑是在css文件中被引用的,你得加上相對路徑參數,在我的文件夾目錄下是這樣的:

各個文件夾結構不相同,你可以靈活選擇。


 

 

三、plugins

這裏用於處理並壓縮文件:

js:

在webpack4-中使用 uglifyjs-webpack-plugin這個插件,然後直接在plugins中使用就ok

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

plugins: {
  new UglifyJsPlugin()
}

optimization(webpack4+)

在webpack4+中移除了 uglifyjs-webpack-plugin 方法,採用optimization中對js壓縮,提取,去重,方法如下:

optimization: {
    minimize: true, //壓縮js,默認使用uglifyjs-webpack-plugin插件
    splitChunks: {
      cacheGroups: { //定義規則
        vendors: { //提取node_modules中對js生成chunk-vndord文件夾
          name: 'chunk-vendors', 
          test: /[\\\/]node_modules[\\\/]/,
          priority: -10,
          chunks: 'all'
        },
        common: { //提取公共部分js生成chunk-common文件夾
          name: 'chunk-common',
          minChunks: 2,
          priority: -20,
          chunks: 'all',
          reuseExistingChunk: true
        },
        styles: { //提取less或css合成一個layout.css文件 
          name: 'layout',
          test: /\.(less|css)$/,
          chunks: 'all',
          minChunks: 1,
          reuseExistingChunk: true,
          enforce: true
        }
      }
    }
  },


最後生成的文件夾目錄結構如下圖:

css:

提取css已經在module中說明,這裏說一下壓縮:安裝插件 optimize-css-assets-webpack-plugin 

const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');



 new OptimizeCSSPlugin({
      cssProcessorOptions: {safe: true, map: {inline: false}}
     }),

html:

 new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html', //本地自定義模板
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true,
      },
      chunksSortMode: 'dependency' //定義引入文件順序,按依賴排序
    }),

其他:

//複製靜態文件
new CopyWebpackPlugin([{
      from: resolve('static'),
      to: resolve('dist/static'),
      ignore: ['.*']
    }]),
//生成文件索引文件
 new ManifestPlugin({
      fileName: 'asset-manifest.json',
    }),

最後,由於每次修改後打包加了hash值,每次文件加都不一樣,就會造成每打包一次就會新增加一個相同文件,類似於這樣:

我們在打包之前先做一步,就是把現有的dist文件夾移除掉,新建一個build.js文件,這裏用到一個插件 rimraf

const webpack = require('webpack');
const path = require('path');
const webpackConfig = require('./webpack.pro.conf');
const rm = require('rimraf');


function resolve(dir) {
  return path.join(__dirname, '..', dir)
}

rm(resolve('dist'), err => {
  if (err) throw err
  webpack(webpackConfig, err => {
    if (err) throw  err
  })
})

構建基本完成,改下命令行:

//package.json
"build": "node config/build.js"

npm run build 就可以生成你的項目生產版本。

這可能是一個最簡單的版本,還可以做很多優化的地方,webpack中還有很多有趣的插件,希望看完不吝指正,多謝!

完整版本請移步:https://github.com/linxner/webpackENV

最後,附上所有webpack.pro.conf.js代碼:

//webpack.pro.conf.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ManifestPlugin = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');




function resolve(dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: resolve('src/main.js'),

  output: {
    path: resolve('dist'),
    filename: 'static/js/[name].[hash:8].js',
    chunkFilename: 'static/js/[name].[hash:8].chunk.js',
    publicPath: "./"
  },

  module: {
    rules: [
      {
        test: /\.(htm|html)$/i,
        use: [{
          loader: 'html-withimg-loader'
        }]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        include: /\src/,
        use: {
          loader: 'babel-loader',
        }
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 10000,
            name: 'static/img/[name].[hash:8].[ext]',
          }
        }]
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'static/media/[name].[ext]'
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'static/fonts/[name].[ext]'
        }
      },
      {
        test: /\.(css|less)$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../../'
            }
          },
          'css-loader',
          {
            loader: require.resolve('postcss-loader'),
            options: {
              ident: 'postcss',
              plugins: () => [
                require('postcss-flexbugs-fixes'),
                autoprefixer({
                  browsers: [
                    '>1%',
                    'last 4 versions',
                    'Firefox ESR',
                    'not ie < 9',
                  ],
                  flexbox: 'no-2009',
                }),
              ],
            },
          },
          'less-loader'
        ],

      },
    ],
  },

  mode: "production",

  optimization: {
    minimize: true,
    splitChunks: {
      cacheGroups: {
        vendors: {
          name: 'chunk-vendors',
          test: /[\\\/]node_modules[\\\/]/,
          priority: -10,
          chunks: 'all'
        },
        common: {
          name: 'chunk-common',
          minChunks: 2,
          priority: -20,
          chunks: 'all',
          reuseExistingChunk: true
        },
        styles: {
          name: 'layout',
          test: /\.(less|css)$/,
          chunks: 'all',
          minChunks: 1,
          reuseExistingChunk: true,
          enforce: true
        }
      }
    }
  },

  plugins: [
    new MiniCssExtractPlugin({
      filename: 'static/css/[name].[hash:8].css',
    }),

    new OptimizeCSSPlugin({
      cssProcessorOptions: {safe: true, map: {inline: false}}
    }),

    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html', //本地自定義模板
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true,
      },
      chunksSortMode: 'dependency'
    }),

    new CopyWebpackPlugin([{
      from: resolve('static'),
      to: resolve('dist/static'),
      ignore: ['.*']
    }]),

    new ManifestPlugin({
      fileName: 'asset-manifest.json',
    }),
  ],
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章