Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support SASS #52

Merged
merged 23 commits into from Apr 21, 2022
Merged

feat: Support SASS #52

merged 23 commits into from Apr 21, 2022

Conversation

ntt261298
Copy link
Collaborator

@ntt261298 ntt261298 commented Apr 16, 2022

Features

  • Support SASS
    • Transform SASS file to CSS content, then create <style> tag with CSS content and append to document.
    • Support configured SASS files by transforming SASS files to CSS files, saving CSS files to cache and serving all CSS files by our preview server.

Todo:

  • Support custom loadPaths: Currently, jest-preview only supports relative scss import via @import, @use. In real projects, we can add custom loadPaths to let sass know where to find the imported files.
  • Support ~ import: Example: @use '~nprogress/nprogress'. This is a feature of sass-loader, or we can add additional config to achieve this. Example in Vite:
  resolve: {
     alias: [
       {
         find: /^~.+/,
         replacement: (val) => {
           return val.replace(/^~/, "");
         },
       },
     ],
   },

@ntt261298 ntt261298 linked an issue Apr 16, 2022 that may be closed by this pull request
Comment on lines 3 to 6
jestPreviewConfigure({
externalCss: ['src/index.css', 'src/global-style.scss'],
sassLoadPaths: ['src'], // Root for @use, @import
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntt261298 Is there any reason we need to move jestPreviewConfigure from setupFilesAfterEnv to setupFiles?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that setupFilesAfterEnv will be run before the transformers, but actually both setupFilesAfterEnv and setupFiles are run before transformers, so I reverted to use setupFilesAfterEnv

@@ -0,0 +1,7 @@
@import './partial-style';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the file is _partial-style.scss (more _). Is this Saas feature or a typo?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/configure.ts Outdated
Comment on lines 28 to 30
if (cssFile.endsWith('.scss') || cssFile.endsWith('.sass')) {
const sass = require('sass');

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not safe since user might not have saas installed locally. Might need to try catch

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, also, sass-loader supports multiple sass implementation (node-sass, dart-sass,...), maybe we can refer to that

src/transform.ts Outdated
Comment on lines 120 to 123
} catch {
// File doesn't exist
sassLoadPaths = JSON.stringify([]);
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we guarantee the error is always File doesn't exist?
Can we assert if the error is exactly that case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can move to use fs.existsSync to check of the config file exists

src/transform.ts Outdated
Comment on lines 126 to 130
const sassSrc = ${JSON.stringify(src)};

const result = sass.compileString(sassSrc, {
loadPaths: ${sassLoadPaths},
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we can compile saas in the transformer to leverage caching feature #51 (now we haven't implemented yet, but we can prepare) instead of run time. CSS Modules (#40) might need to change also.
Do we have any other reason we need to convert saas to run time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have other reason to convert sass to run time, so I move it out of the return string

src/configure.ts Outdated
Comment on lines 51 to 55
// Transform sass to css
const sassDestinationFile = destinationFile.replace(
/\.(scss|sass)$/,
'.css',
);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think move this declaration next to fs.writeFileSync(sassDestinationFile, sassResult.css); is more readable

src/configure.ts Outdated
);
// Example: src/common/styles.css => cache-src___common___styles.css
const delimiter = '___';
const destinationBasename = `cache-${basename.replace('/', delimiter)}`;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will replace the first /.

Suggested change
const destinationBasename = `cache-${basename.replace('/', delimiter)}`;
const destinationBasename = `cache-${basename.replace(/\//g, delimiter)}`;

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this logic correct since we are using basename

src/configure.ts Outdated

// If sass file is included, we need to transform it to css
if (cssFile.endsWith('.scss') || cssFile.endsWith('.sass')) {
const { exec } = require('child_process');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use import here.

src/transform.ts Outdated
sass = require('sass');
} catch (err) {
console.log(err);
return `module.exports = ${JSON.stringify(src)};`;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think fileame is a better option for a fallback.

Copy link
Owner

@nvh95 nvh95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Can you update scss code to also use @use?
  • Can you update scss code to use ~ (e.g:@use '~nprogress/nprogress';) (loading a css file from the nprogress node module)
  • Reading Create React App's scss page gives me a lot of information (@use, how they handle loadPaths via environment variable SASS_PATH, node-sass and LibSass are deprecated, SCSS Modules)
  • Given node-sass and LibSass are deprecated (need more source), let's consider if we need to support those processors. I think the strategy can be: release with Dart Sass, then support other Sass processors in the next releases. If we go with that strategy, remember to mention we are currently support only Dart Sass.
  • Can you update scss code to demo. That folder is to be used for development than examples/vite-react. I think we can add an other example sass to showcase how jest-preview works with sass (The idea is from Next.JS https://github.com/vercel/next.js/tree/canary/examples)

Comment on lines +45 to +54
exec(
`./node_modules/.bin/sass ${cssFile} ${cssDestinationFile} --no-source-map`,
(err: any) => {
if (err) {
console.log(err);
}
},
);
return;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the reason to use exec here is special (try not to run sass in jsdom environment), Can you add a detail comment here? @ntt261298?


// Transform sass to css and save to cache folder
exec(
`./node_modules/.bin/sass ${cssFile} ${cssDestinationFile} --no-source-map`,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a little bad feeling about using ./node_modules/.bin/sass directly. I'm afraid it's not gonna work in some circumstances (e.g: monorepo? but we are not testing for monorepo just yet anyway).

I'm not sure, since this is pretty similar to the problem I have to solve when adding postinstall script.

No clear action items now. I think just to keep this implementation in mind for now.

@@ -11,7 +11,7 @@ module.exports = {
modulePaths: ['<rootDir>/src'],
transform: {
'^.+\\.(ts|js|tsx|jsx)$': '@swc/jest',
'^.+\\.css$': 'jest-preview/transforms/css',
'^.+\\.(css|scss|sass)$': 'jest-preview/transforms/css',
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is to remind not forget to update README.md on CSS transform

@@ -0,0 +1,5 @@
header {
.global-configured-sass {
font-size: 40px;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think we can use text-transform: uppercase; (or add a background color) would make us easy to realize if @import takes place yet. Feel free to leave your option.

Similar to _partial-style.scss

@@ -0,0 +1,7 @@
@import 'partials/partial-style';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand @use and @import are pretty the same, @use is newer with some advantages. So I think we can use both @use and @import in our example to cover more Sass features.

src/configure.ts Outdated
Comment on lines 28 to 33
// Create cache folder if it doesn't exist
if (!fs.existsSync(CACHE_FOLDER)) {
fs.mkdirSync(CACHE_FOLDER, {
recursive: true,
});
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can add an utils.ts file which has createCacheFolderIfNeeded() or something like that. We have this logic in quite many places.

@ntt261298 ntt261298 marked this pull request as ready for review April 19, 2022 15:41
@nvh95 nvh95 mentioned this pull request Apr 21, 2022
6 tasks
Copy link
Owner

@nvh95 nvh95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's ship loadPaths and ~ in the next version.

# Conflicts:
#	examples/vite-react/package-lock.json
@netlify
Copy link

netlify bot commented Apr 21, 2022

Deploy Preview for jest-preview-library canceled.

Name Link
🔨 Latest commit 74d43d2
🔍 Latest deploy log https://app.netlify.com/sites/jest-preview-library/deploys/62614ec5ceebc6000989612d

@nvh95 nvh95 merged commit 08f8827 into main Apr 21, 2022
@nvh95 nvh95 deleted the sass-support branch April 21, 2022 13:13
@nvh95 nvh95 changed the title feat: (In Progress) Support SASS feat: Support SASS Apr 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support SCSS
2 participants