不想看過程可以直接看最后的總結 :)
起因
前天的時候就遇到了一個非常棘手的問題,在高高興興寫完 Vue 項目后,使用 npm link 在別的項目里導入自己的包報錯(這里的變量都用 xxxx 或者 yyyy 來表示啦):
"export 'default' (imported as 'xxx') was not found in 'xxxx
但是如果我從 npm 上下載自己的包是不報錯的,而使用 npm link 本地調試的時候就報上面的錯。而且我還自己點進原文件看了下,npm 下載的和本地 npm link 的 xxx.umd.js 根本就是一毛一樣啊,為什么兩邊的結果不一樣呢?
谷歌了一波后發(fā)現別人也有有同樣的問題:
下面他就說了兩邊出現不同結果的問題:
尤大也回復了,但是他說這不是 vue-cli 的問題,是 webpack 自己沒有將文件轉成 ES6 module 的形式。真的是看的我一臉問號。
為什么報錯
沒辦法,他不說解決方法,我自己總得解決吧。首先將谷歌一下報錯信息,得到的解答是: 同時使用了 import 和 module.exports 語法,所以才報錯。什么?這怎么可能,兩邊的項目肯定都沒這樣用過。除非是。。。。。我引入的那個打包后的文件 xxx.umd.js 是有 module.exports 語句的。
難道真的是 Webpack 沒有轉成 ES6 的問題?
坑:官方文檔
第一反應是官方文檔應該有教怎么打包項目的,里面說不定有答案,所以回去認真讀了下文檔,可是:

woc,Webpack 真的不能轉成 ES6 Module 的啊。所以現在問題變成了:Webpack 將原來的項目打包成 ES5 的版本,然后在新項目里用 import 里引入了帶有 module.exports 語句的文件,從而導致上面的報錯。
坑:Vue CookBook
這時我注意到上面出現同樣問題的大哥說到可以用 Rollup.js 來打包,這就可以打包出 ES6 語法的 JS了。馬上開搞,然后查到了 Vue CookBook:

果然可以打包成 xxxx.esm.js 的方法,但是原來的項目是用 Webpack + Vue 來構建的,使用兩套打包工具真的好嗎?雖然不太好,我試了下,奈何在全局引入 .scss 文件的地方試了一萬個方法都不行,只能放棄這個方法。從頭開始分析。
Webpack 是真的坑
說實話那天我就放棄了,本地調試不行就算了吧,不就搞很多個 npm 版本么。后面還是 Jetbrains 給了我靈感。

今天我想刪除某個文件的時候發(fā)現了這個選項:

Exclude?嗯。。。曾經的我就在 webpack.config.js 里看到過這個選項,好像說是可以不對某些文件進行編譯,這樣就能在 yarn run build 的時候提高性能。再結合一下前面分析的“沒有轉成 ES6 語法”的報錯,好像有點說通了。非常有可能 Webpack 對從 npm 下載下來的文件進行預先編譯,將其轉成 ES6,而本地引入的話沒有預先編譯。
后面我做了如下測試:
- 將 /dist 下所有文件拷到新項目的 /src 里,直接本地引入,同樣報錯。
- 將 /dist 下所有文件拷貝到新項目的 /node_modules 里,直接本地使用
import '/node_modules/xxx/xxx.umd.js'引入,成功! - 在新項目使用
npm link xxx后,在 /node_modules 里用上面的import '/node_modules/xxx/xxx.umd.js'引入,失敗。
再次分析
上面 1 和 2 的測試足以說明我的猜想是對的,Webpack 會對 /node_modules 下的文件進行預先編譯,再引入到真實項目中,這樣就沒有 module.exports 的語句了,所以也就不會報錯了。
但是為什么 3 也失敗呢?我在命令行里輸入 ls -a 也發(fā)現自己的 xxx 包呀,說明我的原來的項目包也在 /node_modules 下呀。后面想到 Mac 的 link 命令,npm link 說不定是創(chuàng)建軟鏈接而已,所以用 Finder 打開新項目的 /node_modules ,果然這是個軟鏈接:

而這個軟鏈接指向的真實地址是本機的別的地址,也就是說這個包不在項目的 /node_modules 文件夾下。所以不會預先被編譯,再次印證上面的猜想。
現在終于真相大白了。
總結
為什么報錯
如果使用下載的 npm package,那么 Webpack 在項目引入前將代碼編譯成 ES6 模塊語法,所以這時候不會報錯。
如果使用 npm link 會將 npm 包放在本機的全局 /node_modules 下,新項目的 /node_modules 下只是一個軟鏈接(快捷方式)。而不在新項目 /node_modules 下的文件都不會預先編譯成 ES6 模塊方法。在項目里引入也就等同于下面代碼:
// B.js
module.exports = {
}
// A.js
import "B.js"
而這兩種語法混合使用就會報錯:
"export 'default' (imported as 'xxx') was not found in 'xxxx
解決方法
我簡單搜索了一下沒找到什么解決方法(真的不知道要怎么搜這種問題了)。所以現在最笨的方法就是每次 yarn run build 后將 /dist 目錄拷到別的項目的 /node_modules 下,然后在那個項目引入就可以了。