手摸手:3秒打包一個(gè)three.js項(xiàng)目(有物證)

關(guān)于 webpack 相關(guān)的文章太多了闸拿,何不一起從零開始手寫一個(gè)配置呢斩芭?

真的3秒能打包一個(gè)three.js項(xiàng)目嗎捌浩?真的滩愁,后面會(huì)提供源文件地址哦俐筋。

要打包的項(xiàng)目是這個(gè)樣子的抡秆。


image

從零開始

關(guān)于 three.js 的安裝和使用部分都省略大溜。

首先是最基礎(chǔ)的差油。我們需要安裝

  1. cross-env 目前最流行的運(yùn)行跨平臺(tái)設(shè)置和使用環(huán)境變量的腳本
  2. webpack + webpack-cli + webpack-dev-server:三'賤'客,項(xiàng)目必備

參考常規(guī)webpack配置結(jié)構(gòu)需要3個(gè)最基礎(chǔ)文件:

  1. webpack 基礎(chǔ)配置文件憾筏,暫命名為 webpack.base.js
  2. webpack 開發(fā)配置文件嚎杨,暫命名為 webpack.dev.js
  3. webpack 打包配置文件,暫命名為 webpack.prod.js

當(dāng)然氧腰,需要把 devprod 中的配置和 base 的配置合并起來(lái)枫浙,安裝個(gè)webpack-merge 吧。

然后配置一下最熟悉的腳本運(yùn)行環(huán)節(jié)吧容贝。通過(guò)--config來(lái)對(duì)標(biāo)配置文件自脯,通cross-env 設(shè)置環(huán)境變量

"dev": "cross-env NODE_ENV=dev webpack-dev-server --config script/webpack.dev.js",
"build": "cross-env NODE_ENV=prod webpack --config script/webpack.prod.js"

好的,初期準(zhǔn)備工作都OK開始配置環(huán)節(jié)斤富。

開始配置

首先是webpack的出入口膏潮。出口設(shè)置為 dist 環(huán)節(jié)簡(jiǎn)單直接上代碼。

  {
    entry: './src/index.js',
    output: {
      filename: '[name].[hash:8].js',
      path: rootResolve('dist'),
      publicPath: '/'
    },
  }

順便配置下別名满力。依然可以直接上代碼

  resolve: {
    extensions: ['.js', '.json'],
    alias: {
      '@': rootResolve('src'),
      '@assets': rootResolve('src/assets'),
    }
  }

然后是關(guān)鍵環(huán)節(jié):loaderplugins

關(guān)于 loader:

  • 樣式上使用 less
    • 需要通過(guò)less-loader 解析 less 因?yàn)?webpack 只能讀懂js
    • 解析完成再通過(guò) postcss-loader 加上瀏覽器前綴
    • 再通過(guò)css-loader 解析css代碼中的 url焕参、@import語(yǔ)法
    • 最后,通過(guò)MiniCssExtractPlugin.loader 生成 .css文件
  • JS 文件使用 babel-loader油额,關(guān)于 babel 文章太多了叠纷,暫略
    • 順便使用 HappyPack 進(jìn)行優(yōu)化加速
    • 為什么不選 thread-loader 呢? (因?yàn)槊植缓寐?tīng) - -! 怪我咯)
  • 其他文件潦嘶,用 url-loader 咯涩嚣。

然后 loader 配置就是這樣的

{
  test: /\.less$/,
  exclude: /(node_modules|bower_components)/,
  loaders: [{
    loader: MiniCssExtractPlugin.loader,
    options: {
      esModule: true,
      hmr: process.env.NODE_ENV === 'dev', // 熱更新
      // publicPath: '../',
    }
  }, 'css-loader', 'postcss-loader', 'less-loader']
},
{
  test: /\.m?js$/,
  exclude: /(node_modules|bower_components)/,
  loader: 'happypack/loader',
  options: {
    id: 'babel',
  }
},
{
  test: /\.(png|jpe?g|gif)(\?.*)?$/,
  use: [{
    loader: 'url-loader',
    options: {
      limit: 8192,
      name: 'assets/img/[hash:8].[ext]'
    }
  }]
}

關(guān)于插件部分,首先是配合上面 loader的相關(guān)插件:HappyPackMiniCssExtractPlugin

new MiniCssExtractPlugin({
  filename: "css/[name].[hash:8].css", // css 路徑
}),
new HappyPack({
  id: 'babel',
  loaders: [{
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env'],
      cacheDirectory: true
    }
  }]
})

當(dāng)然掂僵,我想知道運(yùn)行和打包的進(jìn)度: ProgressPlugin航厚,順便弄個(gè) DefinePlugin 工程化必備插件。最后webpack生成后的代碼注入不能少了 HtmlWebpackPlugin

然后 base 文件的插件結(jié)構(gòu)是這樣的

plugins: [
  new webpack.ProgressPlugin(),
  new webpack.DefinePlugin({
    NODE_ENV: JSON.stringify(process.env.NODE_ENV), // 當(dāng)前使用環(huán)境
    VERSION: JSON.stringify('0.1.0'),
  }),
  new MiniCssExtractPlugin({
    filename: "css/[name].[hash:8].css", // css 路徑
    // chunkFilename: "[id].css",
  }),
  new HappyPack({
    id: 'babel',
    loaders: [{
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env'],
        cacheDirectory: true
      }
    }]
  }),
  new HtmlWebpackPlugin({ template: './src/index.html' })
]

開發(fā)環(huán)境配置

首先開發(fā)環(huán)境 api 代理必不可少锰蓬。那么就是 devServer.proxy了幔睬,順便再定義下開發(fā)環(huán)境端口號(hào)。

devServer: {
  contentBase: path.join(__dirname, "dist"),
  compress: true,
  port: 3333
}

目前也沒(méi)有太多事情芹扭,那么 merge 下再配個(gè) HotModuleReplacementPlugin

merge(base, {
  mode: 'development',
  plugins: [
  ],
  devServer: {
    contentBase: rootResolve("src"),
    compress: true,
    port: 3333
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
})

打包環(huán)境

打包環(huán)境主要做了這幾件事情

  1. 打包優(yōu)化
  2. 分類文件
  3. 刪除冗余

首先是 dll

  1. 定義 dll 配置文件麻顶。 比如:webpack.dll.config.js
    1. 需要定義要打包的庫(kù)和打包的出口
    2. 命名生成后的dll模塊的詳細(xì)要點(diǎn)文件 manifest.dll.json

那么 webpack.dll.config.js 內(nèi)容應(yīng)該是這樣的

{
    // 你想要打包的模塊的數(shù)組
    entry: {
        vendor: ['three']
    },
    output: {
        filename: '[name].dll.js',
        path: distResolve('dll'), // 打包后文件輸出的位置
        library: '[name]_library'
        // 這里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
    },
    plugins: [
        new webpack.DllPlugin({
            name: '[name]_library',
            path: distResolve('dll/manifest.dll.json'),
            context: __dirname
        })
    ]
}
  1. 通過(guò) DllReferencePlugin + json文件 把 dll模塊的詳細(xì)要點(diǎn)告訴 webpack

prod 文件中添加 plugins

new webpack.DllReferencePlugin({
  context: __dirname,
  manifest: require(distResolve('./dll/manifest.dll.json'))
})
  1. 添加腳本運(yùn)行配置
"dll": "webpack --config script/webpack.dll.config.js",

運(yùn)行下 npm run dll舱卡,在 dist/dll 目錄下生成dll相關(guān)文件辅肾,那么 dll 配置也完成了。順便做一些清理工作轮锥,用下 CleanWebpackPlugin

new CleanWebpackPlugin({
  cleanOnceBeforeBuildPatterns: [
    'assets', 'js', 'css', 'index.html', '*.js',
    '!manifest.dll.json', '!vendor.dll.js' // 不刪除 dll 文件
  ],
})

然后是代碼優(yōu)化宛瞄,其實(shí)當(dāng) mode: 'production' 時(shí)已經(jīng)做了很多代碼優(yōu)化相關(guān)的事情了。(我不管,我就是要優(yōu)化 - -!

做一下 js的并行壓縮吧

optimization: {
  minimizer: [
    new TerserWebpackPlugin({
      parallel: true,  // 啟用并行壓縮
      cache: true,    // 啟用緩存
    }),
    new OptimizeCssAssetsPlugin({ // 壓縮css
      cssProcessorOptions: {
        safe: true
      }
    })
  ],
  runtimeChunk: true, // 自動(dòng)拆分runtime文件
  splitChunks: {
    chunks: 'async',
    minSize: 30000,
    automaticNameDelimiter: '~',
    automaticNameMaxLength: 30,
    cacheGroups: {
      defaultVendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  },
}

歐耶份汗,再配置下js的打包后路徑就好了

output: { // JS 路徑
  path: distResolve(),
  filename: 'js/[id].[chunkhash].js',
  chunkFilename: 'js/[name].[chunkhash].js'
},

最后 mergebase 配置。在 dev 時(shí)做過(guò)了... 省略蝴簇。

至此杯活,Webpack配置已經(jīng)大部分完成了,運(yùn)行npm run build打包代碼熬词,1旁钧、2、3互拾。 3秒打包完成了歪今。

為什么只需要3秒呢?雖然上面的配置確實(shí)做了很多優(yōu)化颜矿,但是大部分事情都被表象迷惑了寄猩,具體為何下一章見(jiàn)。

最后

  1. 源碼地址 https://github.com/zhongmeizhi/three-demo
  2. 更多實(shí)戰(zhàn)項(xiàng)目:https://github.com/zhongmeizhi/z-ui
  3. 一個(gè)字一個(gè)字碼出來(lái)的文章骑疆,原創(chuàng)不易田篇,點(diǎn)個(gè)贊唄。
  4. 歡迎關(guān)注公眾號(hào)「前端進(jìn)階課」認(rèn)真學(xué)前端箍铭,一起進(jìn)階泊柬。
image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市诈火,隨后出現(xiàn)的幾起案子兽赁,更是在濱河造成了極大的恐慌,老刑警劉巖冷守,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刀崖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡教沾,警方通過(guò)查閱死者的電腦和手機(jī)蒲跨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)授翻,“玉大人或悲,你說(shuō)我怎么就攤上這事】疤疲” “怎么了巡语?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)淮菠。 經(jīng)常有香客問(wèn)我男公,道長(zhǎng),這世上最難降的妖魔是什么合陵? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任枢赔,我火速辦了婚禮澄阳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘踏拜。我一直安慰自己碎赢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布速梗。 她就那樣靜靜地躺著肮塞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姻锁。 梳的紋絲不亂的頭發(fā)上枕赵,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音位隶,去河邊找鬼拷窜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钓试,可吹牛的內(nèi)容都是我干的装黑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼弓熏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼恋谭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起挽鞠,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤疚颊,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后信认,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體材义,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年嫁赏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了其掂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡潦蝇,死狀恐怖款熬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情攘乒,我是刑警寧澤贤牛,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站则酝,受9級(jí)特大地震影響殉簸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一般卑、第九天 我趴在偏房一處隱蔽的房頂上張望武鲁。 院中可真熱鬧,春花似錦椭微、人聲如沸洞坑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至刽沾,卻和暖如春本慕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侧漓。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工锅尘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人布蔗。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓藤违,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纵揍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子顿乒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容