我正在处理使用Tailwind的SCSS文件,并且一切正常,直到我按照如下规则复制为止
.selector {
@apply .md:mb-6;
}
并出现错误:
CssSyntaxError:/server/app/layout/_footer.scss:6:4:
@apply
不能与.md:mb-6一起使用,因为.md:mb-6嵌套在规则内(@media)。
忘记它应该是
.selector {
@screen md {
@apply .mb-6;
}
}
我以前在其他项目上使用过,没问题。
因此,我使用@screen
规则更新了SCSS文件,但遇到了同样的问题。
因此,我完全删除了该规则,但仍然遇到相同的错误。
然后我尝试删除文件中的所有内容;遇到相同的错误。
然后我从导入的主文件中删除了_footer.scss
;遇到相同的错误。
我什至试图完全删除文件。
即使项目中不再存在该错误,该错误仍指向相同的文件和行号。
错误中的路径也不正确,因为它应该是/server/app/src/scss/layout/
而不是/server/app/layout/
。
有人知道发生了什么吗?
编辑:此后,我用另一个项目中的node_modules
文件夹,pacakge.json
和gulp文件替换了CSS,现在CSS可以编译了,所以好像有什么东西设置有错,尽管我不明白为什么旧的设置(来自https://github.com/nystudio107/craft的旧设置可以正常工作,直到遇到错误,然后直到我替换了错误之后才采取任何措施。
但是为了完整起见,这是旧的设置。
package.json
{
"paths": {
"src": {
"base": "./src/",
"css": "",
"img": "./src/img/",
"js": "./src/js/",
"scss": "./src/scss/"
},
"dist": {
"base": "./public_html/",
"css": "./public_html/assets/css/",
"js": "./public_html/assets/js/",
"fonts": "./public_html/assets/fonts/",
"img": "./public_html/assets/img/"
},
"build": {
"base": "./build/",
"css": "./build/css/",
"js": "./build/js/",
"html": "./build/html/",
"img": "./build/img/"
},
"tailwindcss": {
"src": "./build/css/master.css",
"conf": "./tailwind.js"
},
"scss": [
{
"src": "./src/scss/master.scss"
}
],
"templates": "./public_html/site/templates/"
},
"urls": {
"live": "https://example.com.au/",
"local": "http://example.local/",
"critical": "https://example.com.au/"
},
"vars": {
"siteCssName": "site.combined.min.css",
"scssName": "master.scss",
"cssName": "master.css"
},
"globs": {
"distCss": [
"./node_modules/normalize.css/normalize.css",
"./build/css/*.css"
],
"img": [
"./public_html/assets/img/"
],
"components": [],
"critical": [],
"download": [
{
"url": "https://www.google-analytics.com/analytics.js",
"dest": "./public_html/assets/js/"
}
],
"distJs": [
"./build/js/*.js",
"./node_modules/lazysizes/lazysizes.min.js",
"./node_modules/lazysizes/plugins/bgset/ls.bgset.min.js",
"./node_modules/picturefill/dist/picturefill.min.js"
],
"prismJs": [],
"babelJs": [
"./src/js/*.js"
],
"inlineJs": [
"./node_modules/fg-loadcss/src/loadCSS.js",
"./node_modules/fg-loadcss/src/cssrelpreload.js",
"./node_modules/fontfaceobserver/fontfaceobserver.js",
"./node_modules/loadjs/dist/loadjs.min.js"
]
},
"dependencies": {
"fg-loadcss": "^1.2.0",
"fontfaceobserver": "^2.0.5",
"lazysizes": "^2.0.6",
"loadjs": "^3.6.1",
"normalize.css": "^5.0.0",
"picturefill": "^3.0.2"
},
"devDependencies": {
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.16.0",
"chalk": "^1.1.3",
"critical": "^1.1.0",
"fancy-log": "^1.3.3",
"git-rev-sync": "^1.7.1",
"gulp": "^3.9.0",
"gulp-autoprefixer": "^3.1.0",
"gulp-babel": "^6.1.2",
"gulp-cached": "^1.1.1",
"gulp-concat": "^2.6.0",
"gulp-cssnano": "^2.1.2",
"gulp-debug": "^2.1.2",
"gulp-download": "^0.0.1",
"gulp-favicons": "^2.2.6",
"gulp-filter": "^5.0.1",
"gulp-header": "^1.8.7",
"gulp-if": "^2.0.1",
"gulp-imagemin": "^3.1.1",
"gulp-livereload": "^3.8.1",
"gulp-load-plugins": "^1.3.0",
"gulp-newer": "^1.2.0",
"gulp-plumber": "^1.1.0",
"gulp-postcss": "^7.0.0",
"gulp-print": "^2.0.1",
"gulp-purgecss": "^0.15.0",
"gulp-rename": "^1.2.2",
"gulp-replace": "0.5.4",
"gulp-rev": "^7.1.0",
"gulp-sass": "^3.2.0",
"gulp-size": "^2.1.0",
"gulp-sourcemaps": "^2.2.1",
"gulp-streamify": "1.0.2",
"gulp-uglify": "^1.5.4",
"moment": "^2.14.1",
"pa11y": "^4.11.0",
"tailwindcss": "^0.7.4",
"tailwindcss-visuallyhidden": "^1.0.2",
"vinyl-source-stream": "^1.1.0"
},
"scripts": {
"start": "gulp",
"build": "gulp build"
}
}
gulpfile.js
// jshint esversion: 6
// jshint node: true
"use strict";
// package vars
const pkg = require("./package.json");
// gulp
const gulp = require("gulp");
// load all plugins in "devDependencies" into the variable $
const $ = require("gulp-load-plugins")({
pattern: ["*"],
scope: ["devDependencies"]
});
// error logging
const onError = (err) => {
console.log(err);
};
// Our banner
const banner = (function() {
let result = "";
try {
result = [
"/**",
" * @project <%= pkg.name %>",
" * @author <%= pkg.author %>",
" * @build " + $.moment().format("llll") + " ET",
" * @release " + $.gitRevSync.long() + " [" + $.gitRevSync.branch() + "]",
" * @copyright Copyright (c) " + $.moment().format("YYYY") + ", <%= pkg.copyright %>",
" *",
" */",
""
].join("\n");
}
catch (err) {
}
return result;
})();
// scss - build the scss to the build folder, including the required paths, and writing out a sourcemap
gulp.task("scss", () => {
$.fancyLog("-> Compiling scss");
return gulp.src(pkg.paths.src.scss + pkg.vars.scssName)
.pipe($.plumber({errorHandler: onError}))
.pipe($.sourcemaps.init({loadMaps: true}))
.pipe($.sass({
includePaths: pkg.paths.scss
})
.on("error", $.sass.logError))
.pipe($.cached("sass_compile"))
.pipe($.autoprefixer())
.pipe($.sourcemaps.write("./"))
.pipe($.size({gzip: true, showFiles: true}))
.pipe(gulp.dest(pkg.paths.build.css));
});
// tailwind task - build the Tailwind CSS
gulp.task("tailwind", () => {
$.fancyLog("-> Compiling tailwind css");
return gulp.src(pkg.paths.tailwindcss.src)
.pipe($.postcss([
$.tailwindcss(pkg.paths.tailwindcss.conf),
require("autoprefixer"),
]))
.pipe($.if(process.env.NODE_ENV === "production",
$.purgecss({
extractors: [{
extractor: TailwindExtractor,
extensions: ["html", "php", "inc", "twig", "css", "js"]
}],
whitelist: pkg.globs.purgecssWhitelist,
content: pkg.globs.purgecss
})
))
.pipe(gulp.dest(pkg.paths.build.css));
});
// Custom PurgeCSS extractor for Tailwind that allows special characters in
// class names.
//
// https://github.com/FullHuman/purgecss#extractor
class TailwindExtractor {
static extract(content) {
return content.match(/[A-z0-9-:\/]+/g);
}
}
// css task - combine & minimize any distribution CSS into the public css folder, and add our banner to it
gulp.task("css", ["tailwind", "scss"], () => {
$.fancyLog("-> Building css");
return gulp.src(pkg.globs.distCss)
.pipe($.plumber({errorHandler: onError}))
.pipe($.newer({dest: pkg.paths.dist.css + pkg.vars.siteCssName}))
.pipe($.print())
.pipe($.sourcemaps.init({loadMaps: true}))
.pipe($.concat(pkg.vars.siteCssName))
.pipe($.if(process.env.NODE_ENV === "production",
$.cssnano({
discardComments: {
removeAll: true
},
discardDuplicates: true,
discardEmpty: true,
minifyFontValues: true,
minifySelectors: true
})
))
.pipe($.header(banner, {pkg: pkg}))
.pipe($.sourcemaps.write("./"))
.pipe($.size({gzip: true, showFiles: true}))
.pipe(gulp.dest(pkg.paths.dist.css))
.pipe($.filter("**/*.css"))
.pipe($.livereload());
});
// js task - minimize any distribution Javascript into the public js folder, and add our banner to it
gulp.task("js-app", () => {
$.fancyLog("-> Building js-app");
if (process.env.NODE_ENV === "production") {
const browserifyMethod = $.browserify;
} else {
const browserifyMethod = $.browserifyIncremental;
}
const bundleStream = browserifyMethod(pkg.paths.src.jsApp, {
paths: pkg.globs.jsIncludes,
cacheFile: pkg.paths.build.base + "browserify-cache.json"
})
.transform($.babelify, {presets: ["es2015"]})
.transform($.vueify)
.bundle();
return bundleStream
.pipe($.plumber({errorHandler: onError}))
.pipe($.vinylSourceStream("app.js"))
.pipe($.if(process.env.NODE_ENV === "production",
$.streamify($.uglify())
))
.pipe($.streamify($.header(banner, {pkg: pkg})))
.pipe($.streamify($.size({gzip: true, showFiles: true})))
.pipe(gulp.dest(pkg.paths.dist.js));
});
// babel js task - transpile our Javascript into the build directory
gulp.task("js-babel", () => {
$.fancyLog("-> Transpiling Javascript via Babel…");
return gulp.src(pkg.globs.babelJs)
.pipe($.plumber({errorHandler: onError}))
.pipe($.newer({dest: pkg.paths.build.js}))
.pipe($.babel())
.pipe($.size({gzip: true, showFiles: true}))
.pipe(gulp.dest(pkg.paths.build.js));
});
// inline js task - minimize the inline Javascript into _inlinejs in the templates path
gulp.task("js-inline", ["js-babel"], () => {
$.fancyLog("-> Copying inline js");
return gulp.src(pkg.globs.inlineJs)
.pipe($.plumber({errorHandler: onError}))
.pipe($.if(["*.js", "!*.min.js"],
$.newer({dest: pkg.paths.templates + "_inlinejs", ext: ".min.js"}),
$.newer({dest: pkg.paths.templates + "_inlinejs"})
))
.pipe($.if(["*.js", "!*.min.js"],
$.uglify()
))
.pipe($.if(["*.js", "!*.min.js"],
$.rename({suffix: ".min"})
))
.pipe($.size({gzip: true, showFiles: true}))
.pipe(gulp.dest(pkg.paths.templates + "_inlinejs"))
.pipe($.filter("**/*.js"))
.pipe($.livereload());
});
// js task - minimize any distribution Javascript into the public js folder, and add our banner to it
gulp.task("js", ["js-inline"], () => {
$.fancyLog("-> Building js");
return gulp.src(pkg.globs.distJs)
.pipe($.plumber({errorHandler: onError}))
.pipe($.if(["*.js", "!*.min.js"],
$.newer({dest: pkg.paths.dist.js, ext: ".min.js"}),
$.newer({dest: pkg.paths.dist.js})
))
.pipe($.if(["*.js", "!*.min.js"],
$.uglify()
))
.pipe($.if(["*.js", "!*.min.js"],
$.rename({suffix: ".min"})
))
.pipe($.header(banner, {pkg: pkg}))
.pipe($.size({gzip: true, showFiles: true}))
.pipe(gulp.dest(pkg.paths.dist.js))
.pipe($.filter("**/*.js"))
.pipe($.livereload());
});
// Process data in an array synchronously, moving onto the n+1 item only after the nth item callback
function doSynchronousLoop(data, processData, done) {
if (data.length > 0) {
const loop = (data, i, processData, done) => {
processData(data[i], i, () => {
if (++i < data.length) {
loop(data, i, processData, done);
} else {
done();
}
});
};
loop(data, 0, processData, done);
} else {
done();
}
}
// Process the downloads one at a time
function processDownload(element, i, callback) {
const downloadSrc = element.url;
const downloadDest = element.dest;
$.fancyLog("-> Downloading URL: " + $.chalk.cyan(downloadSrc) + " -> " + $.chalk.magenta(downloadDest));
$.download(downloadSrc)
.pipe(gulp.dest(downloadDest));
callback();
}
// download task
gulp.task("download", (callback) => {
doSynchronousLoop(pkg.globs.download, processDownload, () => {
// all done
callback();
});
});
// Run pa11y accessibility tests on each template
function processAccessibility(element, i, callback) {
const accessibilitySrc = pkg.urls.critical + element.url;
const cliReporter = require("./node_modules/pa11y/reporter/cli.js");
const options = {
log: cliReporter,
ignore:
[
"notice",
"warning"
],
};
const test = $.pa11y(options);
$.fancyLog("-> Checking Accessibility for URL: " + $.chalk.cyan(accessibilitySrc));
test.run(accessibilitySrc, (error, results) => {
cliReporter.results(results, accessibilitySrc);
callback();
});
}
// accessibility task
gulp.task("a11y", (callback) => {
doSynchronousLoop(pkg.globs.critical, processAccessibility, () => {
// all done
callback();
});
});
// imagemin task
gulp.task("imagemin", () => {
$.fancyLog("-> Minimizing images in " + pkg.paths.src.img);
return gulp.src(pkg.paths.src.img + "**/*.{png,jpg,jpeg,gif,svg}")
.pipe($.imagemin({
progressive: true,
interlaced: true,
optimizationLevel: 7,
svgoPlugins: [{removeViewBox: false}],
verbose: true,
use: []
}))
.pipe(gulp.dest(pkg.paths.dist.img));
});
// static assets version task
gulp.task("static-assets-version", () => {
gulp.src(pkg.paths.craftConfig + "general.php")
.pipe($.replace(/'staticAssetsVersion' => (\d+),/g, function(match, p1, offset, string) {
p1++;
$.fancyLog("-> Changed staticAssetsVersion to " + p1);
return "'staticAssetsVersion' => " + p1 + ",";
}))
.pipe(gulp.dest(pkg.paths.craftConfig));
});
// set the node environment to development
gulp.task("set-dev-node-env", function() {
$.fancyLog("-> Setting NODE_ENV to development");
return process.env.NODE_ENV = "development";
});
// set the node environment to production
gulp.task("set-prod-node-env", function() {
$.fancyLog("-> Setting NODE_ENV to production");
return process.env.NODE_ENV = "production";
});
// Default task
gulp.task("default", ["set-dev-node-env","css", "js"], () => {
$.fancyLog("-> Livereload listening for changes");
$.livereload.listen();
gulp.watch([pkg.paths.src.scss + "**/*.scss"], ["css"]);
gulp.watch([pkg.paths.src.css + "**/*.css"], ["css"]);
gulp.watch([pkg.paths.src.js + "**/*.js"], ["js"]);
gulp.watch([pkg.paths.templates + "**/*.{html,htm,twig,php,inc}"], () => {
gulp.src(pkg.paths.templates)
.pipe($.plumber({errorHandler: onError}))
.pipe($.livereload());
});
});
// Production build
gulp.task("build", ["set-prod-node-env", "static-assets-version", "download", "imagemin"]);