[Solo hazlo] Personaliza el cargador de paquetes web para realizar la compilación condicional de las dimensiones del archivo

antecedentes

En vue, puede usar process.env para acceder a las propiedades en el archivo de configuración y encontrar el archivo de configuración correspondiente según los diferentes entornos,

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

Además, en el marco cruzado de subprogramas, por ejemplo mpx, múltiples marcos cruzados también admiten la capacidad de compilar condicionalmente en la dimensión del archivo. documentación de compilación multiplataforma mpx

El documento explica la compilación condicional de la dimensión del archivo . Por ejemplo, hay un componente de mapa de negocios map.mpx en el proyecto WeChat->Alipay. Debido a las grandes diferencias en los estándares de los componentes de mapas nativos en WeChat y Alipay, no se puede traducir a través del marco. Realice directamente la salida multiplataforma. En este momento, puede crear un nuevo map.ali.mpx en la misma ubicación y usar los estándares técnicos de Alipay para el desarrollo en él. El sistema de compilación cargará el correspondiente módulo de acuerdo con el modo compilado actualmente. Cuando el modo es ali , map.ali.mpx se cargará primero, de lo contrario se cargará map.mpx.

Si en el webproyecto , ¿cómo implementamos la función de compilación condicional de la dimensión del archivo ?

necesidad

Este documento implementa esta capacidad con webpack loaderun .

La estructura del directorio del proyecto es la siguiente:

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

// 目录
├── mode
│ ├── bridge.js
│ ├── bridge.dev.js
│ └── bridge.prod.js
├── index.js
复制代码
  • Si está en el entorno de desarrollo (dev), importe el archivo bridge.dev.js en el modo;
  • Si está en el entorno de producción (prod), importe el archivo bridge.prod.js en el modo;
  • En otros entornos, importe el archivo bridge.js en modo;

Esto polymorphism-loaderse lanzó actualmente y se puede instalar usando

Programa

Combina los pasos de implementación en texto y luego convierte el texto en código.

  1. Obtenga el contenido del archivo y haga coincidir la sintaxis del archivo importado, como: import xxx from xxx;
  2. Obtenga la dirección del archivo importado que coincidió con el paso anterior y analice si la carpeta contiene el archivo polimórfico;
  3. Si la hay, reemplace la dirección del archivo importado, si no, no la modifique;

Pase options.modecomo , de la siguiente manera:

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

realizar

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

Defina un getResourcemétodo , pase el sourcecontenido de origen y devuelva el contenido de origen procesado. loaderUtils.getOptionsEl método obtiene la configuración entrante, donde puede obtener los modedatos . La sintaxis del archivo importado se obtiene mediante coincidencia regular y luego la dirección del archivo importado se utils.getContextDatafiltra.La ruta absoluta y el nombre de archivo de la dirección del archivo importado se obtienen por utils.genFileListel método, todos los archivos en la carpeta se obtienen por el método, y luego el procesamiento polimórfico se compara utils.getModeFileNamecon el método.El nombre del archivo, y finalmente coincide si el archivo polimórfico existe en el archivo, y lo reemplaza si existe.

El siguiente es el contenido 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
}

复制代码

Resumir

En la actualidad, esta loaderes la primera versión y hay muchos defectos conocidos, como solo import fromsentencias coincidentes, no hay soporte para archivos de estilo, no hay capacidad para filtrar archivos y solo se ha probado webpack4. Estos problemas se actualizarán e iterarán lentamente en el futuro.

Enlace

código fuente del cargador de polimorfismos

Supongo que te gusta

Origin juejin.im/post/7085127216735977486
Recomendado
Clasificación