webpack + vuecli多頁面打包基於(vue-template-admin)修改

全棧若城發表於2020-11-10

遇見的問題TypeError: Cannot read property ‘tap’ of undefined

先看專案目錄結構 :關於專案的修改及改造 再專案完事的時候會發布的

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

如果你也遇見這個問題的話 這一篇部落格應該完全可以解決
問題描述:

building for sit environment...D:\EVDownload\adminMPA\node_modules\script-ext-html-webpack-plugin\lib\plugin.js:50
      compilation.hooks.htmlWebpackPluginAlterAssetTags.tap(PLUGIN, alterAssetTags);
                                                        ^

TypeError: Cannot read property 'tap' of undefined
    at ScriptExtHtmlWebpackPlugin.compilationCallback (D:\EVDownload\adminMPA\node_modules\script-ext-html-webpack-plugin\lib\plugin.js:50:57)
    at SyncHook.eval [as call] (eval at create (D:\EVDownload\adminMPA\node_modules\tapable\lib\HookCodeFactory.js:19:10), <anonymous>:11:1)
    at SyncHook.lazyCompileHook (D:\EVDownload\adminMPA\node_modules\tapable\lib\Hook.js:154:20)
    at Compiler.newCompilation (D:\EVDownload\adminMPA\node_modules\webpack\lib\Compiler.js:504:26)
    at D:\EVDownload\adminMPA\node_modules\webpack\lib\Compiler.js:540:29
    at AsyncSeriesHook.eval [as callAsync] (eval at create (D:\EVDownload\adminMPA\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
    at AsyncSeriesHook.lazyCompileHook (D:\EVDownload\adminMPA\node_modules\tapable\lib\Hook.js:154:20)
    at Compiler.compile (D:\EVDownload\adminMPA\node_modules\webpack\lib\Compiler.js:535:28)
    at D:\EVDownload\adminMPA\node_modules\webpack\lib\Compiler.js:274:11
    at Compiler.readRecords (D:\EVDownload\adminMPA\node_modules\webpack\lib\Compiler.js:402:11)
    at D:\EVDownload\adminMPA\node_modules\webpack\lib\Compiler.js:271:10
    at AsyncSeriesHook.eval [as callAsync] (eval at create (D:\EVDownload\adminMPA\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
    at AsyncSeriesHook.lazyCompileHook (D:\EVDownload\adminMPA\node_modules\tapable\lib\Hook.js:154:20)
    at D:\EVDownload\adminMPA\node_modules\webpack\lib\Compiler.js:268:19
    at AsyncSeriesHook.eval [as callAsync] (eval at create (D:\EVDownload\adminMPA\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:15:1)
    at AsyncSeriesHook.lazyCompileHook (D:\EVDownload\adminMPA\node_modules\tapable\lib\Hook.js:154:20)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! admin@1.0.0 build:sit: `cross-env NODE_ENV=production env_config=sit node build/build.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the admin@1.0.0 build:sit script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\l\AppData\Roaming\npm-cache\_logs\2020-11-10T02_45_03_911Z-debug.log

這個問題全網只有兩個人寫過部落格 但是不適合我這個 (我也不知道為啥 )
如果你也有這樣的問題可以嘗試下:
第一篇部落格解決辦法發是 webpack 和 webpackServe 及 html-webpack-plugin 版本衝突 這個直接去重寫install 個版本就好了
部落格連結 : https://blog.csdn.net/qq_31290307/article/details/86158770
第二篇部落格解決辦法如下 :
set “html-webpack-plugin”: “^4.0.0-alpha” => “4.0.0-alpha”
remove node_modules
remove package-lock.json
npm install
部落格連結: https://www.cnblogs.com/ybz94/p/9625864.html

以上兩篇部落格如果還不能解決你的問題 那你就跟著我走吧! 以下是我的解決思路
第一點 : 檢查入口檔案 是不是有多餘的東西
列印結果如下 :
在這裡插入圖片描述
對比圖 在這裡插入圖片描述

在這裡我們發現入口檔案 多了幾個js 分別是 errorLog.js 和 permission.js
所以我們要做的操作是 將多餘的js刪除
入口函式寫法如下

//多入口配置
// 通過glob模組讀取views資料夾下的所有對應資料夾下的js字尾檔案,如果該檔案存在
// 那麼就作為入口處理
exports.entries = function() {
  var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
  // console.log(entryFiles ,'entryCha')
  var map = {}
  entryFiles.forEach((filePath) => {
        var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        map[filename] = filePath
  })
  delete map.errorLog ;
  delete map.permission ;

  console.log(map ,'map')
  return map
}

修改完入口檔案後 我再次打包發現問題依舊 , 別灰心繼續搞 , webpack 打包主要就是入口和出口 接下來我們研究下出口檔案函式 我一開始寫法如下 :

//多頁面輸出配置
// 與上面的多頁面入口配置相同,讀取pages資料夾下的對應的html字尾檔案,然後放入陣列中
exports.htmlPlugin = function() {
  // let entryHtml = path.resolve(__dirname + '../dist/*.html')
  let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
  let arr = []
  entryHtml.forEach((filePath) => {
      let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
      let conf = {
          // 模板來源
          template: filePath,
          // 檔名稱
          filename: filename + '.html',
          // 頁面模板需要加對應的js指令碼,如果不加這行則每個頁面都會引入所有的js指令碼
          chunks: ['manifest', 'vendor', filename],
          inject: true,
          templateParameters: {
                BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory,
              },
      }
      if (process.env.NODE_ENV === 'production') {
          conf = merge(conf, {
              minify: {
                  removeComments: true,
                  collapseWhitespace: true,
                  removeAttributeQuotes: true
              },
              chunksSortMode: 'dependency'
          })
      }
      arr.push(new HtmlWebpackPlugin(conf))
  })
  console.log(arr , 'arr')
  return arr
}

我們看下列印的資料對不對

[
  HtmlWebpackPlugin {
    options: {
      template: 'D:/EVDownload/adminMPA/src/views/index/index.html',
      templateContent: false,
      templateParameters: [Object],
      filename: 'index.html',
      hash: false,
      inject: true,
      compile: true,
      favicon: false,
      minify: false,
      cache: true,
      showErrors: true,
      chunks: [Array],
      excludeChunks: [],
      chunksSortMode: 'auto',
      meta: {},
      title: 'Webpack App',
      xhtml: false
    },
    childCompilerHash: undefined,
    childCompilationOutputName: undefined,
    assetJson: undefined,
    hash: undefined,
    version: 4
  },
  HtmlWebpackPlugin {
    options: {
      template: 'D:/EVDownload/adminMPA/src/views/page/page.html',
      templateContent: false,
      templateParameters: [Object],
      filename: 'page.html',
      hash: false,
      inject: true,
      compile: true,
      favicon: false,
      minify: false,
      cache: true,
      showErrors: true,
      chunks: [Array],
      excludeChunks: [],
      chunksSortMode: 'auto',
      meta: {},
      title: 'Webpack App',
      xhtml: false
    },
    childCompilerHash: undefined,
    childCompilationOutputName: undefined,
    assetJson: undefined,
    hash: undefined,
    version: 4
  },
  HtmlWebpackPlugin {
    options: {
      template: 'D:/EVDownload/adminMPA/src/views/pagetwo/pagetwo.html',
      templateContent: false,
      templateParameters: [Object],
      filename: 'pagetwo.html',
      hash: false,
      inject: true,
      compile: true,
      favicon: false,
      minify: false,
      cache: true,
      showErrors: true,
      chunks: [Array],
      excludeChunks: [],
      chunksSortMode: 'auto',
      meta: {},
      title: 'Webpack App',
      xhtml: false
    },
    childCompilerHash: undefined,
    childCompilationOutputName: undefined,
    assetJson: undefined,
    hash: undefined,
    version: 4
  }
]

仔細瞅了一下 , 也沒有大問題 ,但是當我開啟config檔案時 發現我在這裡竟然也設定了build路徑 【奔潰】,那麼再重新修改下打包路徑吧 。
第一步在 webpack.dev.conf.js 裡修改

 plugins: [
    new webpack.DefinePlugin({
      'process.env': require('../config/dev.env')
    }),
    new webpack.HotModuleReplacementPlugin(),
    /* 在這開始插入程式碼*********************************************************/

    new htmlWebpackPlugin({
      filename : 'index.html',//輸出的html路徑
      template : 'index.html', //html模板路徑
      //inject : 'head',  //js檔案在head中,若為body則在body中
      inject : true,
      title : 'index',
      chunks : ['app'], //打包時只打包main和a的js檔案,見entry,注意使用chunks時模板index.html檔案裡面不允許有script標籤,即使註釋掉也會報錯
      templateParameters: {
        BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
      }
    }),
    
  new htmlWebpackPlugin({
    filename : 'page.html',//輸出的html路徑
    template : 'page.html', //html模板路徑
    //inject : 'head',  //js檔案在head中,若為body則在body中
    inject : true,
    title : 'page',
    chunks : ['page'], //打包時只打包main和a的js檔案,見entry,注意使用chunks時模板index.html檔案裡面不允許有script標籤,即使註釋掉也會報錯
    templateParameters: {
      BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
    }
  }),
  new htmlWebpackPlugin({
    filename : 'pagetwo.html',//輸出的html路徑
    template : 'pagetwo.html', //html模板路徑
    //inject : 'head',  //js檔案在head中,若為body則在body中
    inject : true,
    title : 'pagetwo',
    chunks : ['pagetwo'], //打包時只打包main和a的js檔案,見entry,注意使用chunks時模板index.html檔案裡面不允許有script標籤,即使註釋掉也會報錯
    templateParameters: {
      BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
    }
  }),
  /* 在這結束插入程式碼*********************************************************/

    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    new webpack.NoEmitOnErrorsPlugin(),
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
   
  ]
})

因為我這有三個動態專案 目前插如三個 new htmlWebpackPlugin

在webpack.prod.conf.js 裡修改如下

 plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    // extract css into its own file
    new MiniCssExtractPlugin({
      filename: utils.assetsPath('css/[name].[contenthash:8].css'),
      chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
    }),
    /* 開始插入程式碼 ************************************************/
    new HtmlWebpackPlugin({
      filename: config.build.app,
      template: 'index.html',
      inject: true,
      favicon: resolve('favicon.ico'),
      title: 'index',
      templateParameters: {
        BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory
      },
      chunks: ['manifest', 'vendor', 'app'],
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      }
      // default sort mode uses toposort which cannot handle cyclic deps
      // in certain cases, and in webpack 4, chunk order in HTML doesn't
      // matter anyway

    }),
    new HtmlWebpackPlugin({
      filename: config.build.page,
      template: 'page.html',
      inject: true,
      favicon: resolve('favicon.ico'),
      title: 'page',
      templateParameters: {
        BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory
      },
      chunks: ['manifest', 'vendor', 'page'],
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      }
      // default sort mode uses toposort which cannot handle cyclic deps
      // in certain cases, and in webpack 4, chunk order in HTML doesn't
      // matter anyway

    }),
    new HtmlWebpackPlugin({
      filename: config.build.pagetwo,
      template: 'pagetwo.html',
      inject: true,
      favicon: resolve('favicon.ico'),
      title: 'pagetwo',
      templateParameters: {
        BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory
      },
      chunks: ['manifest', 'vendor', 'pagetwo'],
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      }
      // default sort mode uses toposort which cannot handle cyclic deps
      // in certain cases, and in webpack 4, chunk order in HTML doesn't
      // matter anyway

    }),
      /* 結束插入程式碼 ************************************************/
    new ScriptExtHtmlWebpackPlugin({
      //`runtime` must same as runtimeChunk name. default is `runtime`
      inline: /runtime\..*\.js$/
    }),
    // keep chunk.id stable when chunk has no name
    new webpack.NamedChunksPlugin(chunk => {
      if (chunk.name) {
        return chunk.name
      }
      const modules = Array.from(chunk.modulesIterable)
      if (modules.length > 1) {
        const hash = require('hash-sum')
        const joinedHash = hash(modules.map(m => m.id).join('_'))
        let len = nameLength
        while (seen.has(joinedHash.substr(0, len))) len++
        seen.add(joinedHash.substr(0, len))
        return `chunk-${joinedHash.substr(0, len)}`
      } else {
        return modules[0].id
      }
    }),
    // keep module.id stable when vender modules does not change
    new webpack.HashedModuleIdsPlugin(),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ] ,

在這裡也插入程式碼 (註釋裡有標記哦!!!!!!!!!!!)
好了 現在在執行下吧 看看效果咋樣呢?
在這裡插入圖片描述
打包完成 成功啦 !

小記
這個bug 說白了 問題的根點在出口檔案這 , 為什麼會在這呢 ? 相關文件有說 是因為 webpack 新增 hook 屬性 造成的看的我迷迷糊糊的 沒明白 大致就是說你的出口檔案應該怎麼設定啥的。 哎!腦殼疼
為什麼出口檔案不能放在公共的utils 裡呢 ? 目前這樣打包問題雖然解決但是 每次的修改過於複雜 (腦殼疼), 如果有大神的話感謝指導下哈!!!後期我會把這個專案開源 詳細請到個人中心檢視
再此特別鳴謝 @璠哥 (一個溫文爾雅的漂亮妹子) @勁琪 (一個陽光帥氣的小帥哥)

相關文章