From 4b3d111bf7775b307eba4cc66b2f975488a9b8b5 Mon Sep 17 00:00:00 2001
From: fxy060608 <fxy060608@gmail.com>
Date: Mon, 16 Sep 2019 14:43:34 +0800
Subject: [PATCH] feat(cli): support sass-loader v8 #776

---
 packages/uni-cli-shared/lib/scss.js           | 11 ++-
 .../build/css-loader.conf.js                  | 59 ++++++++++++---
 .../vue-cli-plugin-hbuilderx/build/utils.js   | 71 -------------------
 .../vue-cli-plugin-uni/lib/chain-webpack.js   | 24 ++++++-
 packages/vue-cli-plugin-uni/lib/options.js    | 15 ++--
 5 files changed, 91 insertions(+), 89 deletions(-)
 delete mode 100644 packages/vue-cli-plugin-hbuilderx/build/utils.js

diff --git a/packages/uni-cli-shared/lib/scss.js b/packages/uni-cli-shared/lib/scss.js
index 162fa74379..cc5793e183 100644
--- a/packages/uni-cli-shared/lib/scss.js
+++ b/packages/uni-cli-shared/lib/scss.js
@@ -1,3 +1,10 @@
+const semver = require('semver')
+
+let sassLoaderVersion
+try {
+  sassLoaderVersion = semver.major(require('sass-loader/package.json').version)
+} catch (e) {}
+
 const SCSS =
   `
 $uni-color-primary: #007aff;
@@ -100,7 +107,9 @@ $uni-font-size-subtitle: 36rpx
 $uni-color-paragraph: #3F536E // 文章段落颜色
 $uni-font-size-paragraph: 30rpx
 `
+
 module.exports = {
   SCSS,
-  SASS
+  SASS,
+  sassLoaderVersion
 }
diff --git a/packages/vue-cli-plugin-hbuilderx/build/css-loader.conf.js b/packages/vue-cli-plugin-hbuilderx/build/css-loader.conf.js
index b2a6df5ebc..f37700990a 100644
--- a/packages/vue-cli-plugin-hbuilderx/build/css-loader.conf.js
+++ b/packages/vue-cli-plugin-hbuilderx/build/css-loader.conf.js
@@ -1,9 +1,16 @@
+const fs = require('fs')
+const path = require('path')
+
 const {
-  // jsPreprocessOptions,
+  getPlatformScss,
+  getPlatformSass,
   nvueCssPreprocessOptions
-  // htmlPreprocessOptions
 } = require('@dcloudio/uni-cli-shared')
 
+const {
+  sassLoaderVersion
+} = require('@dcloudio/uni-cli-shared/lib/scss')
+
 const nvueStyleLoader = {
   loader: '@dcloudio/vue-cli-plugin-hbuilderx/packages/webpack-uni-nvue-loader/lib/style'
 }
@@ -17,19 +24,49 @@ const postcssLoader = {
   loader: 'postcss-loader',
   options: {
     sourceMap: false,
-    parser: require('postcss-comment'),
-    plugins: [
-      require('postcss-import'),
-      require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
+    parser: require('postcss-comment'),
+    plugins: [
+      require('postcss-import'),
+      require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
     ]
   }
 }
 
+// sass 全局变量
+const isSass = fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, 'uni.sass'))
+const isScss = fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, 'uni.scss'))
+let sassData = isSass ? getPlatformSass() : getPlatformScss()
+
+if (isSass) {
+  sassData = `@import "@/uni.sass"`
+} else if (isScss) {
+  sassData = `${sassData}
+  @import "@/uni.scss";`
+}
+
+const scssLoader = {
+  loader: 'sass-loader',
+  options: {
+    sourceMap: false
+  }
+}
+
 const sassLoader = {
   loader: 'sass-loader',
   options: {
-    sourceMap: false,
-    data: ''
+    sourceMap: false
+  }
+}
+
+if (sassLoaderVersion < 8) {
+  scssLoader.options.data = sassData
+  sassLoader.options.data = sassData
+  sassLoader.options.indentedSyntax = true
+} else {
+  scssLoader.options.prependData = sassData
+  sassLoader.options.prependData = sassData
+  sassLoader.options.sassOptions = {
+    indentedSyntax: true
   }
 }
 
@@ -48,11 +85,11 @@ const stylusLoader = {
   }
 }
 
-function createOneOf (preLoader) {
+function createOneOf (preLoader) {
   const use = [
     nvueStyleLoader,
     preprocessLoader
-  ]
+  ]
   use.push(postcssLoader)
   if (preLoader) {
     use.push(preLoader)
@@ -74,7 +111,7 @@ module.exports = [{
   oneOf: createOneOf()
 }, {
   test: /\.scss$/,
-  oneOf: createOneOf(sassLoader)
+  oneOf: createOneOf(scssLoader)
 }, {
   test: /\.sass$/,
   oneOf: createOneOf(sassLoader)
diff --git a/packages/vue-cli-plugin-hbuilderx/build/utils.js b/packages/vue-cli-plugin-hbuilderx/build/utils.js
deleted file mode 100644
index f3e33d709d..0000000000
--- a/packages/vue-cli-plugin-hbuilderx/build/utils.js
+++ /dev/null
@@ -1,71 +0,0 @@
-function resolve (module) {
-  try {
-    return require.resolve(module)
-  } catch (e) {}
-  return module
-}
-
-exports.cssLoaders = function (options) {
-  options = options || {}
-  const cssLoader = {
-    loader: resolve('css-loader'),
-    options: {
-      sourceMap: options.sourceMap
-    }
-  }
-
-  const postcssLoader = {
-    loader: resolve('postcss-loader'),
-    options: {
-      sourceMap: options.sourceMap
-    }
-  }
-
-  // generate loader string to be used with extract text plugin
-  const generateLoaders = (loader, loaderOptions) => {
-    let loaders = options.useVue ? [cssLoader] : []
-    if (options.usePostCSS) {
-      loaders.push(postcssLoader)
-    }
-    if (loader) {
-      loaders.push({
-        loader: resolve(loader + '-loader'),
-        options: Object.assign({}, loaderOptions, {
-          sourceMap: options.sourceMap
-        })
-      })
-    }
-    if (options.useVue) {
-      return [resolve('vue-style-loader')].concat(loaders)
-    } else {
-      return loaders
-    }
-  }
-
-  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
-  return {
-    less: generateLoaders('less'),
-    sass: generateLoaders('sass', {
-      indentedSyntax: true
-    }),
-    scss: generateLoaders('sass'),
-    stylus: generateLoaders('stylus'),
-    styl: generateLoaders('stylus')
-  }
-}
-
-// Generate loaders for standalone style files (outside of .vue)
-exports.styleLoaders = function (options) {
-  const output = []
-  const loaders = exports.cssLoaders(options)
-
-  for (const extension in loaders) {
-    const loader = loaders[extension]
-    output.push({
-      test: new RegExp('\\.' + extension + '$'),
-      use: loader
-    })
-  }
-
-  return output
-}
diff --git a/packages/vue-cli-plugin-uni/lib/chain-webpack.js b/packages/vue-cli-plugin-uni/lib/chain-webpack.js
index c62dfa7064..956c8bb684 100644
--- a/packages/vue-cli-plugin-uni/lib/chain-webpack.js
+++ b/packages/vue-cli-plugin-uni/lib/chain-webpack.js
@@ -1,5 +1,9 @@
 const path = require('path')
 
+const {
+  sassLoaderVersion
+} = require('@dcloudio/uni-cli-shared/lib/scss')
+
 function resolve (dir) {
   return path.resolve(__dirname, '..', dir)
 }
@@ -10,7 +14,7 @@ module.exports = function chainWebpack (platformOptions) {
     cssPreprocessOptions
   } = require('@dcloudio/uni-cli-shared')
 
-  return function (webpackConfig) {
+  return function (webpackConfig) {
     // 处理静态资源 limit
     webpackConfig.module
       .rule('images')
@@ -59,6 +63,22 @@ module.exports = function chainWebpack (platformOptions) {
       })
     })
 
+    if (sassLoaderVersion >= 8) { // check indentedSyntax
+      // vue cli 3 and sass-loader 8
+      cssTypes.forEach(type => {
+        webpackConfig.module.rule('sass').oneOf(type).use('sass-loader').tap(options => {
+          if (options.indentedSyntax) {
+            if (!options.sassOptions) {
+              options.sassOptions = {}
+            }
+            options.sassOptions.indentedSyntax = true
+            delete options.indentedSyntax
+          }
+          return options
+        })
+      })
+    }
+
     platformOptions.chainWebpack(webpackConfig)
     // define
     webpackConfig
@@ -70,6 +90,6 @@ module.exports = function chainWebpack (platformOptions) {
     if (runByHBuilderX) { // 由 HBuilderX 运行时,移除进度,错误
       webpackConfig.plugins.delete('progress')
       webpackConfig.plugins.delete('friendly-errors')
-    }
+    }
   }
 }
diff --git a/packages/vue-cli-plugin-uni/lib/options.js b/packages/vue-cli-plugin-uni/lib/options.js
index 534bf85371..b22dc4508d 100644
--- a/packages/vue-cli-plugin-uni/lib/options.js
+++ b/packages/vue-cli-plugin-uni/lib/options.js
@@ -1,6 +1,10 @@
 const fs = require('fs')
 const path = require('path')
 
+const {
+  sassLoaderVersion
+} = require('@dcloudio/uni-cli-shared/lib/scss')
+
 module.exports = function initOptions (options) {
   const {
     getPlatformScss,
@@ -13,7 +17,7 @@ module.exports = function initOptions (options) {
 
   // 增加 src/node_modules 解析
   options.transpileDependencies.push(path.resolve(process.env.UNI_INPUT_DIR, 'node_modules'))
-  options.transpileDependencies.push('@dcloudio/uni-' + process.env.UNI_PLATFORM)
+  options.transpileDependencies.push('@dcloudio/uni-' + process.env.UNI_PLATFORM)
   options.transpileDependencies.push('@dcloudio/uni-stat')
 
   if (process.env.UNI_PLATFORM === 'app-plus') {
@@ -55,14 +59,17 @@ module.exports = function initOptions (options) {
   let sassData = isSass ? getPlatformSass() : getPlatformScss()
 
   if (isSass) {
-    sassData = `${sassData}
-  @import "@/uni.sass"`
+    sassData = `@import "@/uni.sass"`
   } else if (isScss) {
     sassData = `${sassData}
   @import "@/uni.scss";`
   }
 
-  options.css.loaderOptions.sass.data = sassData
+  if (sassLoaderVersion < 8) {
+    options.css.loaderOptions.sass.data = sassData
+  } else {
+    options.css.loaderOptions.sass.prependData = sassData
+  }
 
   let userPostcssConfigPath = path.resolve(process.env.UNI_INPUT_DIR, 'postcss.config.js')
   if (fs.existsSync(userPostcssConfigPath)) {
-- 
GitLab