[やるだけ]ファイルサイズの条件付きコンパイルを実現するためにwebpackローダーをカスタマイズする

バックグラウンド

ではvue、 process.envを使用して構成ファイルのプロパティにアクセスし、さまざまな環境に応じて対応する構成ファイルを見つけることができます。

.env
.env.development
.env.production
复制代码

また、アプレットのクロスエンドフレームワークでは、たとえばmpx、複数のクロスエンドフレームワークも、ファイルディメンションで条件付きでコンパイルする機能をサポートしています。mpxクロスプラットフォームコンパイルドキュメント

このドキュメントでは、ファイルディメンションの条件付きコンパイルについて説明しています。たとえば、WeChat-> Alipayプロジェクトにはビジネスマップコンポーネントmap.mpxがあります。WeChatとAlipayのネイティブマップコンポーネントの標準には大きな違いがあるため、フレームワークを介して変換することはできません。クロスプラットフォーム出力を直接実行します。この時点で、同じ場所に新しいmap.ali.mpxを作成し、Alipayの技術標準を使用して開発できます。コンパイルシステムは、対応するをロードします。現在コンパイルされているモードに応じたモジュール。モードがaliの場合、map.ali.mpxが最初にロードされます。それ以外の場合は、map.mpxがロードされます。

webプロジェクトの場合、ファイルディメンションの条件付きコンパイルの機能をどのように実装しますか?

必要

このホワイトペーパーではwebpack loader、。

プロジェクトディレクトリの構造は次のとおりです。

// index.js
import bridge from './mode/bridge.js'

// 目录
├── mode
│ ├── bridge.js
│ ├── bridge.dev.js
│ └── bridge.prod.js
├── index.js
复制代码
  • 開発環境(dev)にある場合は、bridge.dev.jsファイルをモードでインポートします。
  • 実稼働環境(prod)にある場合は、bridge.prod.jsファイルをモードでインポートします。
  • 他の環境では、bridge.jsファイルをモードでインポートします。

これpolymorphism-loaderは現在リリースされており、を使用してインストールできます

プログラム

実装手順をテキストにまとめてから、テキストをコードに変換します。

  1. ファイルの内容を取得し、次のようなインポートされたファイル構文と一致させますimport xxx from xxx
  2. 前の手順で一致したインポートされたファイルのアドレスを取得し、フォルダーにポリモーフィックファイルが含まれているかどうかを調べます。
  3. 存在する場合は、インポートされたファイルアドレスを置き換えます。存在しない場合は、変更しないでください。

次のように、webpackの環境構成options.modeとしてます。

rules: [
    {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [{
            loader: 'polymorphism-loader',
            options: {
                mode: 'prod'
            }
        }]
    }
]
复制代码

達成

const loaderUtils = require('loader-utils')
const utils = require('./utils')

/**
 * 返回处理后的文件源
 * @param {*} source 文件源 
 * @returns {string} 处理后的文件源
 */
function getResource (source) {
  const options = loaderUtils.getOptions(this) || {}
  let resource = source
  let requireFileStatements = source.match(utils.REG.matchRequireStatements)
  if (requireFileStatements && options.mode) {
    for (let i = 0, len = requireFileStatements.length; i < len; i++) {
      let requireFilePath = requireFileStatements[i].match(utils.REG.matchRequireFilePath)[0]
      requireFilePath = requireFilePath.substring(1, requireFilePath.length - 1)
      const { fileName, filePath } = utils.getContextData(this.context, requireFilePath)
      const fileList = utils.genFileList(filePath)
      const modeFileName = utils.getModeFileName(fileName, options.mode)
      if (fileList.some(item => item.indexOf(modeFileName) > -1)) {
        let list = requireFilePath.split('/')
        list.pop()
        list.push(modeFileName)
        resource = resource.replace(requireFilePath, list.join('/'))
        console.log(resource)
      }
    }
  }
  return resource
}

module.exports = function(
  source,
  map,
  meta,
) {
  const resource = getResource.apply(this, [source])
  this.callback(null, resource, map, meta)
}
复制代码

getResourceメソッドを定義し、ソースコンテンツを渡しsource、処理されたソースコンテンツを返します。loaderUtils.getOptionsこのメソッドは、modeデータ。インポートされたファイルの構文は定期的な照合によって取得され、インポートされたファイルのアドレスはフィルターで除外されutils.getContextDataます。インポートされたファイルアドレスの絶対パスとファイル名はutils.genFileListメソッドによって取得され、フォルダー内のすべてのファイルは次に、ポリモーフィック処理がutils.getModeFileNameメソッドます。ファイル名。最後に、ポリモーフィックファイルがファイルに存在するかどうかが照合され、存在する場合は置き換えられます。

以下はutils.jsの内容です

// utils.js

const fs = require("fs")

const REG = {
  replaceFileName: /([^\\/]+)\.([^\\/]+)/i,
  matchRequireStatements: /import.*from.*(\'|\")/g,
  matchRequireFilePath: /(\"|\').*(\"|\')/g
}

/**
 * 返回引入文件的绝对路径 和 文件名
 * @param {string} context 当前加载的文件所在的文件夹路径 /polymorphism-loader/src
 * @param {string} requireFilePath 文件中引入的路径 ./event/event
 * @return {object}
 * filePath: /polymorphism-loader/src/event
 * fileName: event
 */
 function getContextData (context, requireFilePath) {
  function running (contextList, requireFilePathList) {
    if (requireFilePathList.length) {
      const name = requireFilePathList.shift()
      switch (name) {
        case '.':
          return running(contextList, requireFilePathList)
        case '..':
          return running([contextList, contextList.pop()][0], requireFilePathList)
        default:
          return running([contextList, contextList.push(name)][0], requireFilePathList)
      }
    }
    return contextList.join('/')
  }
  let requireFilePathList = requireFilePath.split('/')
  let contextList = context.split('/')
  let fileName = requireFilePathList.pop()
  let filePath = running(contextList, requireFilePathList)
  return {
    fileName: fileName,
    filePath: filePath
  }
}

/**
 * 获取文件夹下所有文件名
 * @param {*} filePath 文件夹路径 
 * @returns {array}
 */
function genFileList (filePath) {
  let filesList = []
  let files = fs.readdirSync(filePath); // 需要用到同步读取
  files.forEach((file) => {
    let states = fs.statSync(filePath + '/' + file)
    // 判断是否是目录,是就继续递归
    if (states.isDirectory()) {
      genFileList(filePath + '/' + file, filesList)
    } else {
      // 不是就将文件push进数组,此处可以正则匹配是否是 .js 先忽略
      filesList.push(file)
    }
  })
  return filesList
}

/**
 * 返回组合多态文件名
 * name.js ===> name.[mode].js
 * @param {*} fileName 
 * @param {*} mode 
 * @returns {string}
 */
function getModeFileName (fileName, mode) {
  let modeFileName = null
  if (fileName.match(REG.replaceFileName)) {
    fileName.replace(REG.replaceFileName, ($1, $2, $3) => {
      modeFileName = $2 + '.' + mode + '.' + $3
    })
  } else {
    modeFileName = fileName + '.' + mode
  }
  return modeFileName
}

module.exports = {
  REG,
  getContextData,
  genFileList,
  getModeFileName
}

复制代码

要約する

現在、これloaderは最初のバージョンであり、一致するimport fromステートメントのみ、スタイルファイルのサポートがない、ファイルをフィルタリングする機能がない、webpack4のみがテストされているなど、多くの既知の欠陥があります。これらの問題は更新され、でゆっくりと繰り返されます。未来。

リンク

ポリモーフィズムローダーのソースコード

おすすめ

転載: juejin.im/post/7085127216735977486