├── LICENSE
├── README.md
├── __info.js
├── __run.js
└── stuff.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Jacob Babich
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
🕶 Add SCSS to Svelte
2 |
3 | [](https://github.com/svelte-add/svelte-add/issues?q=is%3Aopen+is%3Aissue+label%3A%22confirmed+bug%22)
4 | [](https://github.com/svelte-add/svelte-add/issues?q=is%3Aopen+is%3Aissue+label%3A%22support+question%22)
5 |
6 | This is an adder for `svelte-add`; you should [read its `README`](https://github.com/svelte-add/svelte-add#readme) before continuing here.
7 |
8 | ## ➕ Adding SCSS
9 |
10 | This adder's codename is `scss`, and can be used like so:
11 |
12 | ```sh
13 | npx svelte-add@latest scss
14 | ```
15 |
16 | ### 🏞 Supported environments
17 |
18 | This adder supports SvelteKit and Vite-powered Svelte apps (all the environments `svelte-add` currently supports).
19 |
20 | ### ⚙️ Options
21 |
22 | This adder doesn't take any options of its own.
23 |
24 | ## 🛠 Using SCSS
25 |
26 | After the adder runs,
27 |
28 | - You can write SCSS syntax in the `style lang="scss"` blocks in Svelte files.
29 |
30 | - You can write SCSS syntax in the `src/variables.scss` file.
31 |
32 | Variables and mixins written here are automatically available to all other SCSS files and `style lang="scss"` blocks in Svelte files without needing to import this file.
33 |
34 | - You can write SCSS syntax in the `src/app.scss` file.
35 |
36 | This is your global stylesheet because it will be active on every page of your site.
37 |
--------------------------------------------------------------------------------
/__info.js:
--------------------------------------------------------------------------------
1 | import { getViteConfigFilePath } from "../../adder-tools.js";
2 | import { extension } from "./stuff.js";
3 |
4 | export const name = "SCSS";
5 |
6 | export const emoji = "🕶";
7 |
8 | export const usageMarkdown = ['You can write SCSS syntax in the `style lang="scss"` blocks in Svelte files.', 'You can write SCSS syntax in the `src/variables.scss` file.\n\n Variables and mixins written here are automatically available to all other SCSS files and `style lang="scss"` blocks in Svelte files without needing to import this file.', "You can write SCSS syntax in the `src/app.scss` file.\n\n This is your global stylesheet because it will be active on every page of your site."];
9 |
10 | /** @type {import("../..").Gatekeep} */
11 | export const gatekeep = async () => {
12 | return { able: true };
13 | };
14 |
15 | /** @typedef {{}} Options */
16 |
17 | /** @type {import("../..").AdderOptions} */
18 | export const options = {};
19 |
20 | /** @type {import("../..").Heuristic[]} */
21 | export const heuristics = [
22 | {
23 | description: "`sass` is installed",
24 | async detector({ folderInfo }) {
25 | return "sass" in folderInfo.allDependencies;
26 | },
27 | },
28 | {
29 | description: "`vitePreprocess` is set up for SCSS in `svelte.config.js`",
30 | async detector({ readFile }) {
31 | /** @param {string} text */
32 | const preprocessIsProbablySetup = (text) => {
33 | if (!text.includes("vitePreprocess")) return false;
34 |
35 | return true;
36 | };
37 |
38 | const js = await readFile({ path: "/svelte.config.js" });
39 | const cjs = await readFile({ path: "/svelte.config.cjs" });
40 |
41 | if (js.exists) {
42 | return preprocessIsProbablySetup(js.text);
43 | } else if (cjs.exists) {
44 | return preprocessIsProbablySetup(cjs.text);
45 | }
46 |
47 | return false;
48 | },
49 | },
50 | {
51 | description: "`src/app.scss` exists",
52 | async detector({ readFile }) {
53 | const scss = await readFile({ path: "/src/app.scss" });
54 |
55 | return scss.exists;
56 | },
57 | },
58 | {
59 | description: "`src/variables.scss` exists",
60 | async detector({ readFile }) {
61 | const scss = await readFile({ path: "/src/variables.scss" });
62 |
63 | return scss.exists;
64 | },
65 | },
66 | {
67 | description: "Vite is set up to automatically import variables.scss",
68 | async detector({ folderInfo, readFile }) {
69 | /** @param {string} text */
70 | const preprocessIsProbablySetup = (text) => {
71 | if (!text.includes("additionalData")) return false;
72 | if (!text.includes("@use")) return false;
73 | if (!text.includes("src/variables.scss")) return false;
74 |
75 | return true;
76 | };
77 |
78 | const vite = await readFile({ path: `/${getViteConfigFilePath(folderInfo)}` });
79 |
80 | if (preprocessIsProbablySetup(vite.text)) return true;
81 |
82 | return false;
83 | },
84 | },
85 | {
86 | description: "The main file (`src/routes/+layout.svelte` for SvelteKit, `src/main.js` or `src/main.ts` for Vite) imports `src/app.scss`",
87 | async detector({ folderInfo, readFile }) {
88 | if (folderInfo.kit) {
89 | const { text } = await readFile({ path: "/src/routes/+layout.svelte" });
90 |
91 | return text.includes(`../app.${extension}`);
92 | }
93 |
94 | const ts = await readFile({ path: "/src/main.ts" });
95 | if (ts.exists) return ts.text.includes(`./app.${extension}`);
96 |
97 | const js = await readFile({ path: "/src/main.js" });
98 | return js.text.includes(`./app.${extension}`);
99 | },
100 | },
101 | ];
102 |
--------------------------------------------------------------------------------
/__run.js:
--------------------------------------------------------------------------------
1 | import { Comment } from "postcss";
2 | import { setupStyleLanguage, updateViteConfig } from "../../adder-tools.js";
3 | import { setDefault, setPropertyValue } from "../../ast-tools.js";
4 | import { extension, stylesHint, variablesHint } from "./stuff.js";
5 |
6 | /** @type {import("../..").AdderRun} */
7 | export const run = async ({ folderInfo, install, updateCss, updateJavaScript, updateSvelte }) => {
8 | const importVariables = '@use "src/variables.scss" as *;';
9 |
10 | await setupStyleLanguage({
11 | extension,
12 | folderInfo,
13 | mutateSveltePreprocessArgs() {},
14 | stylesHint,
15 | updateCss,
16 | updateJavaScript,
17 | updateSvelte,
18 | });
19 |
20 | await updateViteConfig({
21 | mutateViteConfig(viteConfig) {
22 | const cssConfigObject = setDefault({
23 | object: viteConfig,
24 | default: {
25 | type: "ObjectExpression",
26 | properties: [],
27 | },
28 | property: "css",
29 | });
30 |
31 | if (cssConfigObject.type !== "ObjectExpression") throw new Error("css in Vite config must be an object");
32 |
33 | const preprocessorOptionsConfigObject = setDefault({
34 | object: cssConfigObject,
35 | default: {
36 | type: "ObjectExpression",
37 | properties: [],
38 | },
39 | property: "preprocessorOptions",
40 | });
41 |
42 | if (preprocessorOptionsConfigObject.type !== "ObjectExpression") throw new Error("preprocessorOptions in css in Vite config must be an object");
43 |
44 | const scssConfigObject = setDefault({
45 | object: preprocessorOptionsConfigObject,
46 | default: {
47 | type: "ObjectExpression",
48 | properties: [],
49 | },
50 | property: "scss",
51 | });
52 |
53 | if (scssConfigObject.type !== "ObjectExpression") throw new Error("scss in preprocessorOptions in css in Vite config must be an object");
54 |
55 | setPropertyValue({
56 | object: scssConfigObject,
57 | property: "additionalData",
58 | value: {
59 | type: "Literal",
60 | value: importVariables,
61 | },
62 | });
63 | },
64 | updateJavaScript,
65 | folderInfo,
66 | });
67 |
68 | await updateCss({
69 | path: `/src/variables.${extension}`,
70 | async style({ postcss }) {
71 | postcss.prepend(
72 | new Comment({
73 | text: variablesHint,
74 | }),
75 | );
76 |
77 | return {
78 | postcss,
79 | };
80 | },
81 | });
82 |
83 | await install({ package: "sass" });
84 |
85 | if (!folderInfo.kit) await install({ package: "@sveltejs/vite-plugin-svelte" });
86 | };
87 |
--------------------------------------------------------------------------------
/stuff.js:
--------------------------------------------------------------------------------
1 | export const extension = "scss";
2 | export const stylesHint = "Write your global styles here, in SCSS syntax. Variables and mixins from the src/variables.scss file are available here without importing";
3 | export const variablesHint = "Variables and mixins declared here will be available in all other SCSS files";
4 |
--------------------------------------------------------------------------------