1. 程式人生 > >rollup打包js的注意點-haorooms部落格分享

rollup打包js的注意點-haorooms部落格分享

前言

rollup比較適合打包js的sdk或者封裝的框架等,例如,vue原始碼就是rollup打包的。webpack比較適合打包一些應用,例如SPA或者同構專案等等。最近我們對rollup小試牛刀了一下。簡單分享一些注意事項吧。

rollup基礎

rollup基礎知識及外掛的一些使用,網上有不少資料,可以去查閱。

rollup中文網:www.rollupjs.com/guide/zh#-d…

問題記錄吧

下面主要記錄一下rollup使用過程中的一些報錯及解決方案吧。

錯誤一:

You must supply options.name for IIFE bundles

出現這個報錯,是要在options中指定name,例如如下:

  output: {
    file: resolve(`js/haorooms.${type}.js`),
    format: type,
    name: 'haorooms',
    banner
  },
複製程式碼

錯誤二

[!] (commonjs plugin) SyntaxError: Unexpected token

出現這個問題,可能有幾個原因

1、rollup-plugin-commonjs未引入,或者載入循序不對

我們知道,webpack loader是有載入循序的(從右到左,從下到上),rollup雖然沒有嚴格的載入循序,但是我通常是將commonjs放到babel編譯之後。如下:

   babel({
      exclude: 'node_modules/**', // 排除node_modules 下的檔案
      runtimeHelpers: true
    }),
    commonjs(),
複製程式碼

2、缺少babel類 我按照babel類熟悉編譯外掛作為這個專案的依賴。

 npm install --save-dev babel-plugin-transform-class-properties
複製程式碼

.babelrc配置如下:

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
  "plugins": ["transform-runtime", "external-helpers","transform-class-properties"]
}
複製程式碼

注:上面的配置是babel 7.0以下的方式,假如babel7.0以上,用另外的方式配置,參見:babeljs.io/docs/en/v7-…

blog.zfanw.com/babel-js/

錯誤三

code: 'BAD_BUNDLE_TRANSFORMER', plugin: 'uglify'

這個問題比較坑爹,其實我用rollup打包demo程式碼是沒有問題的,但是打包我的js就有問題了,好奇怪,後來我發現是swiper的問題,因為我依賴了swiper。關於swiper打包,在webpack中也有問題,通常babel打包之後,並不會把swiper的es6語法轉換。有時候webapck也會報錯,大致是

dom7 undefined ..
複製程式碼

webpack解決方案如下:

 resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'swiper': 'swiper/dist/js/swiper.js',
      '@': resolve('src')
    }
  },
複製程式碼

指定一個別名

但是發現rollup中好像沒有這個方式,無奈,我在引入swiper的時候如下處理

import Swiper from 'swiper/dist/js/swiper.js'
複製程式碼

這樣打包的時候就不會有問題了。

錯誤四

process not defined
複製程式碼

這個錯誤是在打包成功之後,瀏覽器執行發現的,發現打包之後的程式碼中有process.env.NODE_ENV

解決方案:

import replace from 'rollup-plugin-replace'

const env = process.env.NODE_ENV
plugins: [
 replace({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
]
複製程式碼

把 process.env.NODE_ENV這個替換掉

rollup 批量打包的方式

我們用rollup打包,一般都會打如下方式

amd – 非同步模組定義,用於像RequireJS這樣的模組載入器
cjs – CommonJS,適用於 Node 和 Browserify/Webpack
es – 將軟體包儲存為ES模組檔案
iife – 一個自動執行的功能,適合作為<script>標籤。(如果要為應用程式建立一個捆綁包,您可能想要使用它,因為它會使檔案大小變小。)
umd – 通用模組定義,以amd,cjs 和 iife 為一體
複製程式碼

我是用node,迴圈讀取的方式,配置如下:

const babel = require('rollup-plugin-babel')
const node = require('rollup-plugin-node-resolve')
const commonjs = require('rollup-plugin-commonjs')
const json = require('rollup-plugin-json')
const replace = require('rollup-plugin-replace')
const uglify = require('rollup-plugin-uglify')
// 新增 rollup-plugin-postcss 外掛
const postcss = require('rollup-plugin-postcss')
// 新增 postcss plugins
const simplevars = require('postcss-simple-vars')
const nested = require('postcss-nested')
const cssnext = require('postcss-cssnext')
const cssnano = require('cssnano')
const version = process.env.VERSION || require('../package.json').version
const path = require('path')
const fs = require('fs')
const ora = require('ora')
const terser = require('terser')
const zlib = require('zlib')
const spinner = ora('building for production...')
spinner.start()
const rollup = require('rollup')
if (!fs.existsSync('dist')) {
  fs.mkdirSync('dist')
}
function resolve(dir) {
  return path.join(__dirname, '..', dir)
}
const banner =
  '/*!\n' +
  ` * haoroomsjssdk v${version}\n` +
  ` * (c) 2017-${new Date().getFullYear()}\n` +
  ' * Released under the MIT License.\n' +
  ' */'

  // amd – 非同步模組定義,用於像RequireJS這樣的模組載入器
  // cjs – CommonJS,適用於 Node 和 Browserify/Webpack
  // es – 將軟體包儲存為ES模組檔案
  // iife – 一個自動執行的功能,適合作為<script>標籤。(如果要為應用程式建立一個捆綁包,您可能想要使用它,因為它會使檔案大小變小。)
  // umd – 通用模組定義,以amd,cjs 和 iife 為一體
const buildArray = ['amd', 'cjs', 'iife', 'umd']

let allConfig = []
const env = process.env.NODE_ENV
let baseConfig = {
  plugins: [
    postcss({
      extensions: ['.css'],
      plugins: [
        simplevars(),
        nested(),
        cssnext({ warnForDuplicates: false }),
        cssnano()
      ]
    }),
    node({
      jsnext: true, // 該屬性是指定將Node包轉換為ES2015模組
      // main 和 browser 屬性將使外掛決定將那些檔案應用到bundle中
      main: true, // Default: true
      browser: true // Default: false
    }),
    json(),
    babel({
      exclude: 'node_modules/**', // 排除node_modules 下的檔案
      runtimeHelpers: true
    }),
    commonjs(),
    replace({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
    (env === 'production' && uglify())
  ]
}
buildArray.forEach(item => {
  let outputs = {
    input: resolve('src/haorooms.js'),
    output: {
      file: resolve(`js/haorooms.${item}.min.js`),
      format: item,
      name: 'haorooms',
      banner
    }
  }
  allConfig.push(Object.assign({}, baseConfig, outputs))
})

function build (builds) {
  let built = 0
  const total = builds.length
  const next = () => {
    buildEntry(builds[built]).then(() => {
      built++
      if (built < total) {
        next()
      } else {
        spinner.stop()
      }
    }).catch(logError)
  }

  next()
}

function buildEntry (config) {
  const output = config.output
  const { file, banner } = output
  const isProd = /min\.js$/.test(file)
  return rollup.rollup(config)
    .then(bundle => bundle.generate(output))
    .then(({ code }) => {
      if (isProd) {
        const minified = (banner ? banner + '\n' : '') + terser.minify(code, {
          output: {
            ascii_only: true
          },
          compress: {
            pure_funcs: ['makeMap']
          }
        }).code
        return write(file, minified, true)
      } else {
        return write(file, code)
      }
    })
}

function write (dest, code, zip) {
  return new Promise((resolve, reject) => {
    function report (extra) {
      console.log(blue(path.relative(process.cwd(), dest)) + ' ' + getSize(code) + (extra || ''))
      resolve()
    }

    fs.writeFile(dest, code, err => {
      if (err) return reject(err)
      if (zip) {
        zlib.gzip(code, (err, zipped) => {
          if (err) return reject(err)
          report(' (gzipped: ' + getSize(zipped) + ')')
        })
      } else {
        report()
      }
    })
  })
}

function getSize (code) {
  return (code.length / 1024).toFixed(2) + 'kb'
}

function logError (e) {
  console.log(e)
}

function blue (str) {
  return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'
}

build(allConfig)
複製程式碼

執行的時候直接如下:

cross-env NODE_ENV=production node 上面的檔名
複製程式碼

備註:cross-env 可以指定環境變數等

另外一種方式是用npm run all

參見地址:www.npmjs.com/package/npm…

可以用這個來執行多個npm 命令,來達到執行一次,打包所有的功能!

文章出處:

本文來源haorooms部落格:www.haorooms.com/post/rollup…