Compile SASS into WXSS using Webpack and insert it into the applet page

The company’s e-commerce small program project is a little old, has been using the original writing method, due to various reasons, can not use other technology stack reconstruction, every time writing WXSS is very uncomfortable, so I have this idea

Problem point 1: Applets have one WXSS file per page, so how do webpack compilations output multiple WXSS files

If wepback is configured with multiple entries, it will output multiple exit files. So there are as many entries as there are SCSS files in the project.

  1. inapp.jsonDefines the page paths of the main package and the subpackage, directly traversing to get their directory names
// pages and subPackages
const { pages, subPackages } = appJson

// Extract the main package directory name
// "pages/homeDelivery/index" => "pages/homeDelivery"
/ / / / ^ / + (? ! .*\/)/ remove the content after the last slash
const dirList = pages.map(page= > page.replace(/ [^ /] + (? ! . * / / /).' '))

// Extract the subcontract directory name
// "pages/paySuccess/index" => "fightGroups/pages/paySuccess/index" => "fightGroups/pages/paySuccess"
subPackages.forEach(sub= > {
  const{ pages, root } = sub dirList.push(... pages.map(subPage= > `${root}/${subPage}`.replace(/ [^ /] + (? ! . * / / /).' ')))})Copy the code

Obtain all SCSS/SASS files by traversing the files in the directory

  1. Plus the components directory, recursively traverses all files in this directory, returning if it is SCSS /sass

  2. Extract the WXSS file: MiniCssExtractPlugin

plugins: [
  // ...
  new MiniCssExtractPlugin({
    // redefine the suffix name
    filename: '[name].wxss'})]Copy the code

Problem # 2: The Webpack package outputs a [name].js file by default, but we don’t need it

FixStyleOnlyEntriesPlugin using this plugin, will remove webpack pack out [name]. Js, and will not affect the original js file

Problem # 3: Hot updates

Enable webpack’s Watch function

watchOptions: {
  // Ignore all files except SCSS to reduce listening pressure
  ignored: [/node_modules/.'*.js'.'*.css'.'*.wxml'.'*.wxss'.'*.wxs'.'*.json']},Copy the code

If the SCSS file is modified, it will be repackaged and compiled to achieve hot update. Provides two shell commands, one for one-time builds and one for hot updates

"build": "cross-env build_type=buildOnce webpack --config webpack.config.js"."watch": "cross-env build_type=buildConstantly webpack --config webpack.config.js"
Copy the code

Problem point 4: package compilation of applets

  1. add.gitignoreignorenode_modules
  2. project.config.jsonthroughpackOptionsSetting up the packaging configuration, we need to ignorenode_modules.webpack.config.js.package.json.package-lock.json
  3. project.config.jsonthroughpackOptionsSet hot update, same as above
"packOptions": {
    "ignore": [{"type": "folder"."value": "node_modules"
        },
        {
            "type": "file"."value": "webpack.config.js"
        },
        {
            "type": "file"."value": "package.json"
        },
        {
            "type": "file"."value": "package-lock.json"}},"watchOptions": {
    "ignore": [
        "webpack.config.js"."package.json"."package-lock.json"."node_modules/**/**"]},Copy the code

Complete WebPack configuration

const path = require('path')
const fs = require('fs')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries");
const appJson = require('./app.json')

const baseConfig = {
  mode: 'development'.watch: process.env.build_type === 'buildConstantly'.watchOptions: {
    // Ignore all files except SCSS
    ignored: [/node_modules/.'*.js'.'*.css'.'*.wxml'.'*.wxss'.'*.wxs'.'*.json']},module: {
    rules: [{test: /\.s(a|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader, 'css-loader'.'sass-loader']],}},plugins: [
    new FixStyleOnlyEntriesPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].wxss'}})]const genExportInfo = (parseFileList) = > {
  if(! parseFileList.length)return []
  return parseFileList.map(pathInfo= > {
    return {
      entry: {
        index: path.resolve(__dirname, pathInfo),
      },
      output: {
        path: path.resolve(__dirname, path.dirname(pathInfo)) }, ... baseConfig, } }) }/ * * *@desc Recursively get all files in the directory *@param {String} Dir Specifies the directory path *@param {RegExp} SuffixReg Specifies that the suffix name is regular. /^.*$/ indicates that * passes all matches@param {Array} list 
 * @returns {Array} Return the file path */
const recursiveFile = (dir, suffixReg = $/ / ^. *, list = []) = > {
  const readList = fs.readdirSync(dir)
  readList.forEach(r= > {
    const filePath = path.join(dir, r)
    if (fs.statSync(filePath).isFile()) {
      const fileSuffix = path.extname(filePath).slice(1)
      suffixReg.test(fileSuffix) && list.push(filePath)
    } else {
      recursiveFile(filePath, suffixReg, list)
    }
  })
  return list
}

/ * * *@desc CSS file path source: app.json pages and subPackages, components */
const genCssPathList = (appJson) = > {
  // pages and subPackages
  const { pages, subPackages } = appJson

  // Extract the main package directory name
  // "pages/homeDelivery/index" => "pages/homeDelivery"
  / / / / ^ / + (? ! .*\/)/ remove the content after the last slash
  const dirList = pages.map(page= > page.replace(/ [^ /] + (? ! . * / / /).' '))

  // Extract the subcontract directory name
  // "pages/paySuccess/index" => "fightGroups/pages/paySuccess/index" => "fightGroups/pages/paySuccess"
  subPackages.forEach(sub= > {
    const{ pages, root } = sub dirList.push(... pages.map(subPage= > `${root}/${subPage}`.replace(/ [^ /] + (? ! . * / / /).' ')))})const needToParseList = []

  // Extract all components filesneedToParseList.push(... recursiveFile(path.resolve(__dirname,'./components'), /s(a|c)ss/))
  
  dirList.forEach(dir= >{ needToParseList.push(... recursiveFile(path.resolve(__dirname, dir),/s(a|c)ss/))})return needToParseList
}

module.exports = genExportInfo(genCssPathList(appJson))

Copy the code