airyland / vux

Mobile UI Components based on Vue & WeUI
https://vux.li
MIT License
17.59k stars 3.71k forks source link

是否能考虑支持happypack #2492

Open Jiiiiiin opened 6 years ago

Jiiiiiin commented 6 years ago

@airyland vux贡献者们 新年好~。~

因为业务代码太多,打包时间已经递增到9分钟,尝试了一下happypack,降低了很多,但是发现,vux-loader就没能干预构建过程,导致使用了未进行[按需引入]的版本。

相同模块使用happypack的效果:

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

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 } })

const webpackConfig = { context: path.resolve(__dirname, '../'), entry: { app: './src/main.js' }, output: { path: config.build.assetsRoot, filename: '[name].js', chunkFilename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, resolve: { extensions: ['.js', '.vue', '.json', '.less', '.styl'], alias: { '@': resolve('src'), '@assets': resolve('src/assets'), '@api': resolve('src/api'), '@transcode-types': resolve('src/api/transcode-types.js'), '@mutation-types': resolve('src/store/mutation-types.js'), '@styl': resolve('src/assets/styl'), '@comp': resolve('src/components'), '@ccomp': resolve('src/base/comm'), '@bcomp': resolve('src/base/business'), '@store': resolve('src/store') } }, module: { rules: [ ...(config.dev.useEslint ? [createLintingRule()] : []), { test: /.vue$/, loader: 'vue-loader', options: vueLoaderConfig // options: {...vueLoaderConfig, // loaders: { // js: 'happypack/loader?id=js' // } // }, }, { test: /.js$/, loader: 'babel-loader', // loader: ['happypack/loader?id=js'], include: [resolve('src'), resolve('test'), resolve('node_modules/vue-echarts-v3/src'), resolve('node_modules/webpack-dev-server/client'), resolve('node_modules/vue-viewplus/src/')] }, //... }, // plugins: [ // new HappyPack({ // id: 'js', // loaders: ['babel-loader?cacheDirectory=true'], // threadPool: happyThreadPool // }) // ], 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' } }

const vuxLoader = require('vux-loader') const vuxConfig = require('./vux-config') module.exports = vuxLoader.merge(webpackConfig, vuxConfig)


使用之后的配置:
```js
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length})
const merge = require('webpack-merge')

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

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
  }
})

const webpackConfig = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    chunkFilename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json', '.less', '.styl'],
    alias: {
      '@': resolve('src'),
      '@assets': resolve('src/assets'),
      '@api': resolve('src/api'),
      '@transcode-types': resolve('src/api/transcode-types.js'),
      '@mutation-types': resolve('src/store/mutation-types.js'),
      '@styl': resolve('src/assets/styl'),
      '@comp': resolve('src/components'),
      '@ccomp': resolve('src/base/comm'),
      '@bcomp': resolve('src/base/business'),
      '@store': resolve('src/store')
    }
  },
  module: {
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        // options: vueLoaderConfig
        options: {...vueLoaderConfig,
          loaders: {
            js: 'happypack/loader?id=js'
          }
        },
      },
      {
        test: /\.js$/,
        // loader: 'babel-loader',
        loader: ['happypack/loader?id=js'],
        include: [resolve('src'), resolve('test'), resolve('node_modules/vue-echarts-v3/src'), resolve('node_modules/webpack-dev-server/client'), resolve('node_modules/vue-viewplus/src/')]
      },
     //....
  },
  plugins: [
    new HappyPack({
      id: 'js',
      loaders: ['babel-loader?cacheDirectory=true'],
      threadPool: happyThreadPool
    })
  ],
  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'
  }
}

const vuxLoader = require('vux-loader')
const vuxConfig = require('./vux-config')
module.exports = vuxLoader.merge(webpackConfig, vuxConfig)
airyland commented 6 years ago

记得之前 vue-loader 不支持 happypack,还没有研究过

fxjs commented 6 years ago

大神新年好,我的项目构建也递增到 10分钟以上了,用HappyPack立马降到60s内,由于vux-loader在编译时未支持HappyPack,打包出来的文件大小有误,还请大神百忙之中抽点时间解决这个问题呢,大型项目需要您的技术支持,谢谢!


var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')
var vuxLoader = require('vux-loader')
var isProduction = process.env.NODE_ENV === 'production'

var HappyPack = require('happypack') // #优化
var os = require('os')
var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }) // <-

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

const webpackConfig = {
  entry: {
    // app: './src/main.js',
    app: ['babel-polyfill', './src/main.js']
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: isProduction
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'assets': path.resolve(__dirname, '../src/assets'),
      'comps': path.resolve(__dirname, '../src/components'),
      'views': path.resolve(__dirname, '../src/views'),
      'api': path.resolve(__dirname, '../src/api'),
      'store': path.resolve(__dirname, '../src/store'),
      'theme': isProduction
        ? path.resolve(__dirname, `../src/themes/${config.build.theme}`)
        : path.resolve(__dirname, `../src/themes/${config.dev.env.theme}`)
    }
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        // use: 'happypack/loader?id=vueLoader'
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: ['babel-loader?cacheDirectory=true'], // #1优化打包速度 - 'babel-loader'
        // use: 'happypack/loader?id=js',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 5000,
          name: utils.assetsPath('img/[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]')
        }
      }
    ]
  }
  // plugins: [
  //   new HappyPack({
  //     id: 'vueLoader',
  //     threadPool: happyThreadPool,
  //     verbose: true,
  //     loaders: [{
  //       loader: 'vue-loader',
  //       options: vueLoaderConfig
  //     }]
  //   }),
  //   new HappyPack({
  //     id: 'js',
  //     threadPool: happyThreadPool,
  //     verbose: true,
  //     loaders: ['babel-loader?cacheDirectory=true']
  //   })
  // ]
}

module.exports = vuxLoader.merge(webpackConfig, {
  options: { showVuxVersionInfo: false },
  cache: true, // #2优化
  plugins: [
    'vux-ui',
    new webpack.optimize.CommonsChunkPlugin({ // #3优化 效果明显
      async: 'shared-module',
      minChunks: (module, count) => (
        count >= 2    // 当一个模块被重复引用2次或以上的时候单独打包起来。
      )
    })
  ]
})```
Jiiiiiin commented 6 years ago

我们的项目也是这样,一个银行app,路由组织如下,已经将近百个页面:

期望老大也往今年也往一些细节方面深入一下,不单单针对这个问题 :)

@fxjs 可以试试dll 也可以优化一些。

现在我只能是在dev模式下开启happy,vue-loader直接使用happy我的项目会出现问题,我只是把涉及js的处理进行了处理,效果还可以,针对生产打包的时候还是没有使用:

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length})
const merge = require('webpack-merge')

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

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
  }
})

console.log('process.env.NODE_ENV', process.env.NODE_ENV === 'production')

// 解决vux-loader不支持的问题 https://github.com/airyland/vux/issues/2492
const createVueLoaderOptions = () => {
  if(process.env.NODE_ENV === 'production'){
    return vueLoaderConfig
  } else {
    return {...vueLoaderConfig,
      loaders: {
        js: 'happypack/loader?id=js'
      }
    }
  }
}

const createJsLoaders = () => {
  if(process.env.NODE_ENV === 'production'){
    return 'babel-loader'
  } else {
    return ['happypack/loader?id=js']
  }
}

const webpackConfig = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    chunkFilename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json', '.less', '.styl'],
    alias: {
      '@': resolve('src'),
      '@assets': resolve('src/assets'),
      '@api': resolve('src/api'),
      '@transcode-types': resolve('src/api/transcode-types.js'),
      '@mutation-types': resolve('src/store/mutation-types.js'),
      '@styl': resolve('src/assets/styl'),
      '@comp': resolve('src/components'),
      '@ccomp': resolve('src/base/comm'),
      '@bcomp': resolve('src/base/business'),
      '@store': resolve('src/store')
    }
  },
  module: {
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: createVueLoaderOptions(),
      },
      {
        test: /\.js$/,
        loader: createJsLoaders(),
        include: [resolve('src'), resolve('test'), resolve('node_modules/vue-echarts-v3/src'), resolve('node_modules/webpack-dev-server/client'), resolve('node_modules/vue-viewplus/src/')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[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]')
        }
      }
    ]
  },
  plugins: [
    ...(process.env.NODE_ENV === 'production' ? []: [new HappyPack({
      id: 'js',
      loaders: ['babel-loader?cacheDirectory=true'],
      threadPool: happyThreadPool
    })]),
  ],
  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'
  }
}

const vuxLoader = require('vux-loader')
const vuxConfig = require('./vux-config')
module.exports = vuxLoader.merge(webpackConfig, vuxConfig)
airyland commented 6 years ago

近期研究一下。目前自己的使用一直是推送后服务器自动构建,因此在构建时间方面没有太大感觉。

Jiiiiiin commented 6 years ago

@airyland 某些企业的老系统架构,你懂得,根本不允许搞自动化集成,自己的机器性能就到那了,这一块对我们这种应用还是有很大需求,当然这不能说是vux需要做的工作; 感谢!

fxjs commented 6 years ago

问题解决了,根源是多处引入了 'router' 导致router实例N次引起,实例router非常耗时!!目前降到了150s-

chengzi1222 commented 6 years ago

@fxjs 你解决了吗?跟路由有关系???? 我的情况和你的差不多。happypack就对vue和js用了、原先本地10分钟,现在26秒。打包出来的文件全是null,文件连1kb都没有 image

image 能请问你怎么解决的吗?大神,求助,搞了一周了。我们的项目也是非常大

fxjs commented 6 years ago

@chengzi1222 1、排查代码是否有多处 import router .. ;2、使用dll抽取公共库如vue、axios、lodash等

chengzi1222 commented 6 years ago

@fxjs , import router .只有两处,dll抽取公共库已经做过了。。。。现在就是尝试多线程,happypack对vue-loader,好像不能解析, image @Jiiiiiin 请问,你的happypack'对vue-loader用起了吗? image

Jiiiiiin commented 6 years ago

@chengzi1222 还等着作者修复呢 哈哈

Jiiiiiin commented 6 years ago

目前上面的配置只能用于dev模式,prod还不支持

ron0115 commented 6 years ago

@chengzi1222 你好 请问你dll.config是怎么配置的,我抽取vux的时候报一对错,主要是以下两种 image

JokerLZD commented 5 years ago

@ron0115 请问你的 dll 成功了吗 我的也报这些错误