1. 程式人生 > >記一次webpack4.x項目配置

記一次webpack4.x項目配置

ack 設置 註意 可視化分析 bubuko window att 位置 ocs

在自構建自己的個人頁面的時候使用到webpack4,遇到了一些問題,查看了大佬們的文章以及官方文檔,在這裏總結一下。

webpack比較基礎的東西就不贅述了,代碼裏面的註釋也會輔助說明,先看一下目錄結構:

│  .babelrc
│  .gitignore
│  package-lock.json
│  package.json
│  README.en.md
│  README.md
│      
├─build
│      webpack.common.js
│      webpack.dev.js
│      webpack.prod.js
│      webpack.rules.js
│                
└─src
    ├─assets
    │      test.json
    │      
    ├─common
    │  ├─css
    │  ├─fonts
    │  ├─images
    │  └─js
    └─pages
        ├─my
        │      index.html
        │      index.js
        │      index.styl
        │      
        └─other
                index.html
                index.js
                index.styl
                

這裏目錄結構導出如果有不知道的同學,其實很簡單,windows命令 tree /f 導出當前目錄包括文件夾名字,tree /f > catalog.txt 導入到一個txt文本。

1.webpack整體配置

像大部分同學的習慣一樣,在build文件夾裏面分為幾個webpack配置,common基礎公用配置,dev開發環境配置,prod生產環境配置,以及單獨分離出來的rule配置各項loader。

//common
module.exports = (env) => {
  return {
    entry: {},
    plugins: [],
    optimization: {
}, module: {} } };
//dev
module.exports = merge(common(‘development‘), { mode: ‘development‘, devtool: ‘inline-source-map‘, output: {}, devServer: {}, plugins: [], });
//prod
module.exports = merge(common(‘production‘), { mode: ‘production‘, output: {}, plugins: [ ], });

這裏webpack4 推薦用mode聲明開發環境還是生產環境,這裏是作為一個全局變量,而不是node環境,所以如果要在配置裏面用到全局變量,用函數返回

技術分享圖片

這裏我是直接定義的變量,然後在引用的時候傳入參數,不是官方所定義的全局變量,其實這樣寫不是很好,既然分離了環境那就應該在不同的配置文件中寫配置。

2.多頁面entry配置和html模版插件

webpack裏面的entry

    entry: {
      // 多入口文件
      my: [
        ‘./src/pages/my/index.js‘,
      ],
      other: [
        ‘./src/pages/other/index.js‘,
      ]
    },

在外部定義多個頁面的信息,以及html-webpack-plugin模版插件的函數進行批量操作

/*可多頁面配置*/
const htmlArray = [
  {
    _html: ‘my‘,
    title: ‘我的首頁‘,
    // chunks: [‘my‘]
  },
  {
    _html: ‘other‘,
    title: ‘其他‘,
    // chunks: [‘other‘]
  }
];
// 獲取html-webpack-plugin參數的方法
let getHtmlConfig = function (name, title, globalEnv) {
  return {
    template: `./src/pages/${name}/index.html`,
    filename: `${name}.html`,
    // favicon: ‘./favicon.ico‘,
    title: title,
    inject: true,
    hash: false, //開啟hash  ?[hash]

    /*chunk 裏面配置的文件才會在html中引入,所以有其他引入的話要註意加上,
    比如runtime和splitChunks裏面的vendor等,建議不要這個,默認加載所有的*/
    // chunks: chunks,

    minify: globalEnv === "development" ? false : {
      removeComments: true, //移除HTML中的註釋
      collapseWhitespace: true, //折疊空白區域 也就是壓縮代碼
      removeAttributeQuotes: true, //去除屬性引用
    },
  };
};

在webpack plugin裏面引入執行html模版

      //自動生成html模板
      ...htmlArray.map((element) => {
        return new HtmlWebpackPlugin(getHtmlConfig(element._html, element.title, env));
      }),

3.module.rules loader加載器

由於loader比較多,可以單獨提取到一個配置文件

    css,css預處理器loader,MiniCssExtractPlugin是webpack4分離css的插件,後面再提到

  1.     {
          test: /\.(css|styl)$/,
          // 區別開發環境和生成環境
          /*用了MiniCssExtractPlugin,不要用style-loader,沖突*/
          use: env === "development" ?
            ["style-loader", "css-loader", "stylus-loader"] :
            [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"]
        },

  2.     {
          test: /\.js$/,
          exclude: "/node_modules/",
          use: [{
            loader: "babel-loader",
            options: {
              /*可使用禁止在每個文件註入runtime,避免文件多而大,采用babel-plugin-transform-runtime輔助提取引用
               *  plugins: [‘@babel/transform-runtime‘]*/
    
              // 配置在 .babelrc 中,和browserslist
              // presets: [‘@babel/preset-env‘]
            }
          }]
        },

    這裏是base64轉換和輸入位置,更多配置可以看官網

  3.     {
          test: /\.(png|jpg|gif)$/,
          use: [{
            // url-loader包含file-loader
            loader: "url-loader",
            options: {
              limit: 5 * 1024, //小於5k時將會已base64位圖片打包處理
              // 圖片文件輸出的文件夾
              outputPath: "images"
            }
          }]
        },

    字體和html的 loader

  4.     {
          test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
          loader: ‘url-loader‘,
          options: {
            limit: 10000,
            /*原來的名字和後綴*/
            name: ‘[name].[ext]‘,
            // 文件輸出的文件夾
            outputPath: "fonts"
          }
        },
        {
          test: /\.html$/,
          // html中的img標簽
          use: ["html-withimg-loader"]
        },

4. plugin

common 裏面,第一個是html模版,上面講過了,第二三個顧名思義。

    plugins: [

      //自動生成html模板
      ...htmlArray.map((element) => {
        return new HtmlWebpackPlugin(getHtmlConfig(element._html, element.title, env));
      }),

      // 消除冗余的css代碼
      new PurifyCssWebpack({
        paths: glob.sync(path.join(__dirname, "../src/pages/*/*.html"))
      }),

      //靜態資源輸出
      new CopyWebpackPlugin([{
        from: path.resolve(__dirname, "../src/assets"),
        to: ‘./assets‘,
        ignore: [‘.*‘]
      }]),


    ],

dev,這裏官方提示使用這裏完全啟發devServer熱更新,我沒深入研究,同誌們可以研究一下。

  plugins: [
    //熱更新,配合devserver服務完全啟動HMR
    new webpack.HotModuleReplacementPlugin(),

    // new BundleAnalyzerPlugin(),     //性能優化 高大上的可視化分析模塊
  ],

技術分享圖片

prod,清理dist的插件有一點小變動,提取css的插件官方建議被替代,以及仍然需要額外的插件壓縮css

  plugins: [

    /*刪除dist目錄,2.0後默認了output的path,這裏無需填寫*/
    new CleanWebpackPlugin({
      root: path.resolve(__dirname, ‘../‘), //根目錄
      // verbose Write logs to console.
      verbose: true, //開啟在控制臺輸出信息
    }),

    /*webpack用這個代替ExtractTextPlugin,提取,開發環境我沒分離*/
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: ‘[name].[contenthash].css‘,
      // chunkFilename: ‘[id].[contenthash].css‘,
    }),
    //壓縮css
    new OptimizeCSSPlugin(),

  ],

5. 代碼壓縮和分離

    /*代碼分離 壓縮,webpack4x集成部分插件和選項*/
    optimization: {
      /*壓縮js代碼入口,是否開啟minimizer,
       例如TerserWebpackPlugin插件,性能比UglifyJSPlugin好
       默認引入生產模式為true,所以不用操作,可以手動開啟和調節minimizer選項*/
      // minimize: false

      /*將運行時代碼拆分為單獨的塊。
       將其設置single為為所有塊創建單個運行時包
       單頁面
       runtimeChunk: ‘single‘,
       */

      /*多頁面別名*/
      runtimeChunk: {
        name: entryPoint => `runtimechunk~${entryPoint.name}`
      },
      /*分離公共代碼*/
      splitChunks: {
        /*緩存chunk 提取公共模塊復用*/
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: ‘vendors‘,
            chunks: ‘all‘
          }
        }
      },
    },

6. 開發環境devServer

  devServer: {
    contentBase: path.join(__dirname, "../dist"),
    publicPath:‘/‘,
    host: "127.0.0.1",
    port: "5199",
    overlay: true, // 瀏覽器頁面上顯示錯誤
    // open: true, // 開啟瀏覽器  open: ‘Google Chrome‘
    // stats: "errors-only", //stats: "errors-only"表示只打印錯誤:
    hot: true, // 開啟熱更新
    // compress: true,   //開啟gzip
  },

7. 生產環境 output 輸出

  output: {
    path: path.resolve(__dirname, ‘../dist‘),
    // 打包多出口文件
    // 生成 a.bundle.[hash].js  b.bundle.[hash].js
    // hash工程級整個是一樣的,chunkhash模塊級有依賴的文件是一樣的,contenthash根據自身的內容生成hash,每個文件都不一樣
    filename: ‘./js/[name].[contenthash].js‘,
    publicPath: ‘./‘
  },

8. js 語法和api轉換編譯

  開發依賴

"@babel/cli": "^7.2.3",
"@babel/core": "^7.3.4",
"@babel/plugin-transform-runtime": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"babel-loader": "^8.0.5",

生產也需要的依賴
"dependencies": {
"@babel/polyfill": "^7.2.5",
"@babel/runtime": "^7.3.4"
}
其中runtime官方的說法是節約代碼以及生成器語法的轉換,如果不用這兩個使用async和await會報錯。

技術分享圖片技術分享圖片

然後在.babelrc中使用,關於 @babel/polyfill 的使用,這裏配合 @babel/preset-env 有三種使用方式,這裏usage會自動根據代碼轉換,安裝後不要引入。

技術分享圖片

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage"
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-transform-runtime"
  ]
}

最後在package.json或者單獨建立browserslist文件來限制瀏覽器版本和轉換操作

"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
],




最後啟動和大概測試了下,沒發現什麽問題。
由於時間和能力有限,可能有很多沒考慮到,不夠深入理解,還有一些冗余甚至錯誤的地方望各位大佬指正。

參考:

1,多頁面配置,參考的是這位大佬的文章。https://segmentfault.com/a/1190000014984842

2,webpack官方文檔,可以統一看一遍。https://webpack.js.org/plugins/mini-css-extract-plugin/

3,babel相關官方文檔 https://babeljs.io/docs/en/babel-polyfill#docsNav

附:

1,在線配置webpack的頁面,常用的依賴,插件和代碼分割以及安裝命令等。https://webpack.jakoblind.no/

time:2019-02-15

記一次webpack4.x項目配置