[Just do it] Personnalisez le chargeur Webpack pour réaliser une compilation conditionnelle des dimensions du fichier

Contexte

Dans vue, vous pouvez utiliser process.env pour accéder aux propriétés du fichier de configuration et rechercher le fichier de configuration correspondant en fonction des différents environnements,

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

Toujours dans le framework cross-end d'applet, par exemple mpx, plusieurs frameworks cross-end prennent également en charge la possibilité de compiler de manière conditionnelle dans la dimension de fichier. documentation de compilation multiplateforme mpx

Le document explique la compilation conditionnelle de la dimension du fichier . Par exemple, il existe un composant de carte d'entreprise map.mpx dans le projet WeChat->Alipay. En raison des grandes différences dans les normes des composants de carte natifs dans WeChat et Alipay, ils ne peut pas être traduit via le framework. Effectuer directement une sortie multiplateforme. À ce stade, vous pouvez créer un nouveau map.ali.mpx au même emplacement et utiliser les normes techniques d'Alipay pour le développement. Le système de compilation chargera le fichier correspondant module selon le mode actuellement compilé. Lorsque le mode est ali , map.ali.mpx sera chargé en premier, sinon map.mpx sera chargé.

Si dans le webprojet , comment implémente-t-on la fonction de compilation conditionnelle de la dimension fichier ?

avoir besoin

Cet article implémente cette fonctionnalité avec webpack loaderun .

La structure du répertoire du projet est la suivante :

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

// 目录
├── mode
│ ├── bridge.js
│ ├── bridge.dev.js
│ └── bridge.prod.js
├── index.js
复制代码
  • S'il est dans l'environnement de développement (dev), importez le fichier bridge.dev.js dans le mode ;
  • S'il est dans l'environnement de production (prod), importez le fichier bridge.prod.js dans le mode ;
  • Dans d'autres environnements, importez le fichier bridge.js en mode ;

Ceci polymorphism-loaderest actuellement publié et peut être installé à l'aide de

Programme

Combinez les étapes d'implémentation en texte, puis convertissez le texte en code.

  1. Obtenez le contenu du fichier et faites correspondre la syntaxe du fichier importé, telle que : import xxx from xxx;
  2. Obtenez l'adresse du fichier importé correspondant à l'étape précédente et vérifiez si le dossier contient le fichier polymorphe ;
  3. Si c'est le cas, remplacez l'adresse du fichier importé, sinon ne la modifiez pas ;

Passez options.modeen , comme suit :

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

accomplir

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)
}
复制代码

Définissez une getResourceméthode , transmettez le sourcecontenu source et renvoyez le contenu source traité. loaderUtils.getOptionsLa méthode obtient la configuration entrante, où vous pouvez obtenir les modedonnées . La syntaxe du fichier importé est obtenue par correspondance régulière, puis l'adresse du fichier importé est filtrée utils.getContextData. Le chemin absolu et le nom de fichier de l'adresse du fichier importé sont obtenus par utils.genFileListla méthode , tous les fichiers du dossier sont obtenus par le méthode, puis le traitement polymorphe est mis en correspondance par la utils.getModeFileNameméthode Le nom du fichier, et correspond enfin si le fichier polymorphe existe dans le fichier, et le remplace s'il existe.

Voici le contenu de 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
}

复制代码

Résumer

À l'heure actuelle, il loaders'agit de la première version et il existe de nombreux défauts connus, tels que des import fromdéclarations de correspondance uniquement, l'absence de prise en charge des fichiers de style, l'absence de possibilité de filtrer les fichiers et seul webpack4 a été testé. Ces problèmes seront mis à jour et itérés lentement dans l'avenir.

Lien

code source du chargeur de polymorphisme

Je suppose que tu aimes

Origine juejin.im/post/7085127216735977486
conseillé
Classement