GithubHelp home page GithubHelp logo

n0th1ng-else / svelte-preprocess Goto Github PK

View Code? Open in Web Editor NEW

This project forked from sveltejs/svelte-preprocess

0.0 0.0 0.0 1.55 MB

Baked in support for common used preprocessors

TypeScript 100.00%

svelte-preprocess's Introduction

Svelte Preprocess

A Svelte preprocessor with support for: PostCSS, SCSS, Less, Stylus, Coffeescript, TypeScript and Pug.

Installation

npm install -D svelte-preprocess

The preprocessor module installation is up to the developer.

  • babel: npm install -D @babel/core @babel/preset-...
  • coffeescript: npm install -D coffeescript
  • typescript: npm install -D typescript
  • postcss: npm install -D postcss postcss-load-config
  • less: npm install -D less
  • sass: npm install -D node-sass or npm install -D sass
  • pug: npm install -D pug
  • stylus: npm install -D stylus

Note: If you want to load your postcss configuration from a external file, make sure to also install postcss-load-config.

Features

Template tag

Add vue-like support for defining your markup between a <template> tag. The tagname can be customized to something like markup for example. See #options.

Note: only for auto preprocessing

<template>
  <div>Hey</div>
</template>

<style></style>

<script></script>

External files

<template src="./template.html"></template>
<script src="./script.js"></script>
<style src="./style.css"></style>

Global style

Add a global attribute to your style tag and instead of scoping the CSS, all of its content will be interpreted as global style.

<style global>
  div {
    color: red;
  }
</style>

Note1: needs PostCSS to be installed.

Note2: if you're using it as a standalone processor, it works best if added to the end of the processors array.

Note3: if you need to have some styles be scoped inside a global style tag, use :local in the same way you'd use :global.

Global rule

Use a :global rule to only expose parts of the stylesheet:

<style lang="scss">
  .scoped-style {
  }

  :global {
    @import 'global-stylesheet.scss';

    .global-style {
      .global-child-style {
      }
    }
  }
</style>

Works best with nesting-enabled CSS preprocessors, but regular CSS selectors like div :global .global1 .global2 are also supported.

Note1: needs PostCSS to be installed.

Note2: if you're using it as a standalone processor, it works best if added to the end of the processors array.

Note3: wrapping @keyframes inside :global {} blocks is not supported. Use the -global- name prefix for global keyframes.

Preprocessors

Current supported out-of-the-box preprocessors are SCSS, Stylus, Less, Coffeescript, TypeScript, Pug, PostCSS, Babel.

<template lang="pug">
  div Posts
  +each('posts as post')
    a(href="{post.url}") {post.title}
</template>

<script lang="typescript">
  // Compatible with Svelte v3...
  export const hello: string = 'world';
</script>

<style src="./style.scss"></style>

<!-- Or -->

<style lang="scss">
  $color: red;
  div {
    color: $color;
  }
</style>

Modern Javascript syntax

svelte-preprocess allows you to run your component code through babel before sending it to the compiler, allowing you to use new language features such as optional operators and nullish coalescing. However, note that babel should transpile your component code to the javascript version supported by the Svelte compiler, so ES6+.

For example, with @babel/preset-env your config could be:

import preprocess from 'svelte-preprocess'
  ...
  preprocess: preprocess({
    babel: {
      presets: [
        [
          '@babel/preset-env',
          {
            loose: true,
            // No need for babel to resolve modules
            modules: false,
            targets: {
              // ! Very important. Target es6+
              esmodules: true,
            },
          },
        ],
      ],
    },
  });
  ...

Note: If you want to transpile your app to be supported in older browsers, you must run babel from the context of your bundler.

Replace values

Replace a set of string patterns in your components markup by passing an array of [RegExp, ReplaceFn | string], the same arguments received by the String.prototype.replace method.

In example, to add process.env.{prop} value resolution and a custom @if/@endif if-block shorthand, one could do:

sveltePreprocess({
  replace: [
    [
      /process\.env\.(\w+)/g,
      (_:, prop) => JSON.stringify(process.env[prop]),
    ],
    [/@if\s*\((.*?)\)$/gim, '{#if $1}'],
    [/@endif$/gim, '{/if}'],
  ],
});

Which allows to write your component like:

@if(process.env.NODE_ENV !== 'development')
<h1>Production environment!</h1>
@endif

And the result, for a NODE_ENV = 'production' would be:

{#if "production" !== 'development'}
  <h1>Production environment!</h1>
{/if}

Note1: the replace transformer is executed before any other transformer.

Note2: it is NOT recommended to modify Svelte's syntax.

Usage

With rollup-plugin-svelte

// rollup.config.js
import svelte from 'rollup-plugin-svelte';
import autoPreprocess from 'svelte-preprocess'
import { scss, coffeescript, pug } from 'svelte-preprocess'

export default {
  ...,
  plugins: [
    svelte({
      /**
       * Auto preprocess supported languages with
       * '<template>'/'external src files' support
       **/
      preprocess: autoPreprocess({ /* options */ })
      /**
       * It is also possible to manually enqueue
       * stand-alone processors
       * */
      preprocess: [
        pug({ /* pug options */ }),
        scss({ /* scss options */ }),
        coffeescript({ /* coffeescript options */ })
      ]
    })
  ]
}

With svelte-loader

  ...
  module: {
    rules: [
      ...
      {
        test: /\.(html|svelte)$/,
        exclude: /node_modules/,
        use: {
          loader: 'svelte-loader',
          options: {
            preprocess: require('svelte-preprocess')({ /* options */ })
          },
        },
      },
      ...
    ]
  }
  ...

With Sapper

Sapper has two build configurations, one for the client bundle and one for the server. To use svelte-preprocess with Sapper, you need to define it on both configurations.

// ...
import sveltePreprocess from 'svelte-preprocess';

const preprocess = sveltePreprocess({
  postcss: true,
  // ...
});

export default {
  client: {
    plugins: [
      svelte({
        preprocess,
        // ...
      }),
  },
  server: {
    plugins: [
      svelte({
        preprocess,
        // ...
      }),
    ],
  },
};

With Svelte VS Code

svelte-vscode needs to know how its (svelte) language server should preprocess your files. This can be achieved by creating a svelte.config.js file at the root of your project which exports a svelte options object (similar to svelte-loader and rollup-plugin-svelte).

Example:

// svelte.config.js
import sveltePreprocess from 'svelte-preprocess';

module.exports = {
  preprocess: sveltePreprocess({
    // ...svelte-preprocess options
  }),
  // ...other svelte options
};

Tip: this file can be imported in your bundle config instead of having multiple svelte configurations lying around.

Preprocessing modes

svelte-preprocess can be used in two ways: auto preprocessing and with stand-alone processors.

Auto Preprocessing

In auto preprocessing mode, svelte-preprocess automatically uses the respective preprocessor for your code based on your type="..." or lang="..." attributes. It also handles the <template> tag for markup, external files and global styling. It's as simple as importing the module and executing the default exported method.

import preprocess from 'svelte-preprocess'

...
  {
    /* svelte options */
    ...,
    preprocess: preprocess({ /* options */ }),
  }
...

Svelte v3 has added support for multiple processors, so it's also possible to use svelte-preprocess with other preprocessors:

import preprocess from 'svelte-preprocess'
import { mdsvex } from 'mdsvex'
...
  {
    /* svelte options */
    ...,
    preprocess: [
      preprocess({ /* svelte-preprocess options */ }),
      mdsvex({ /* mdsvex options */ })
    ],
  }
...

Standalone processors

In case you want to manually configure your preprocessing step, svelte-preprocess exports these named processors:

  • pug
  • coffeescript
  • typescript
  • less
  • scss or sass
  • stylus
  • postcss
  • babel
  • globalStyle - transform <style global> into global styles and supports :global nested selectors.
  • replace - replace string patterns in your markup.
import { scss, coffeescript, pug, globalStyle } from 'svelte-preprocess';

svelte.preprocess(input, [pug(), coffeescript(), scss(), globalStyle()]);

Every processor accepts an option object which is passed to its respective underlying tool.

import { scss, postcss } from 'svelte-preprocess';

svelte.preprocess(input, [
  scss(),
  postcss({
    plugins: [
      require('autoprefixer')({
        browsers: 'last 2 versions',
      }),
    ],
  }),
]);

Note: there's no built-in support for <template> tag when using standalone processors.

Options

svelte-preprocess in auto-processing mode can receive an options object.

import svelte from 'svelte';
import sveltePreprocess from 'svelte-preprocess';
const options = {
  /**
   * Define which tag should `svelte-preprocess` look for markup content.
   *
   * This is only used if you desire to define your markup between this tag
   * or to import it from a external file.
   *
   * The example below means your markup can be defined inside a `<markup>` tag.
   **/
  markupTagName: 'markup',
  /**
   * Extend the default language alias dictionary.
   * Each entry must follow: ['alias', 'languageName']
   */
  aliases: [
    /**
     * Means
     * <... src="./file.cst"> or
     * <... lang="cst"> or
     * <... type="text/customLanguage">
     * <... type="application/customLanguage">
     * will be treated as the language 'customLanguage'
     */
    ['cst', 'customLanguage'],
  ],

  preserve: [
    /**
     * Using the same matching algorithm as above, don't parse,
     * modify, or remove from the markup, tags which match the
     * language / types listed below.
     * **/
    'ld+json',
  ],

  /** Disable a language by setting it to 'false' */
  scss: false,

  /** or pass an option to render synchronously and any other node-sass or sass options*/
  scss: {
    renderSync: true,
    /** Explicitly set the scss implementation to use */
    implementation: require('sass'),
  },

  /**  Pass options to the default preprocessor method */
  stylus: {
    paths: ['node_modules'],
  },

  /**
   * Post process css with PostCSS by defining 'transformers.postcss' property,
   * either pass 'true' to activate PostCSS transforms and use the `postcss.config.js`
   */
  postcss: true,

  /** or pass an object with postcss plugins and their options directly. */
  postcss: {
    plugins: [require('autoprefixer')({ browsers: 'last 2 versions' })],
  },

  typescript: {
    /**
     * Optionally specify the directory to load the tsconfig from
     */
    tsconfigDirectory: './configs',

    /**
     * Optionally specify the full path to the tsconfig
     */
    tsconfigFile: './tsconfig.app.json',

    /**
     * Optionally specify compiler options.
     * These will be merged with options from the tsconfig if found.
     */
    compilerOptions: {
      module: 'es2015',
    },

    /**
     * Type checking can be skipped by setting 'transpileOnly: true'.
     * This speeds up your build process.
     */
    transpileOnly: true,
  },

  /** Use a custom preprocess method by passing a function. */
  pug({ content, filename, attributes }) {
    const code = pug.render(content);

    return { code, map: null };
  },

  /** Add a custom language preprocessor */
  customLanguage({ content, filename, attributes }) {
    const { code, map } = require('custom-language-compiler')(content);

    return { code, map };
  },

  /** Replace string patterns in your markup */
  replace: [
    // Replace `process.env.{prop}` with the actual stringified value.
    [
      /process\.env\.(\w+)/g,
      (_: string, match: string) => JSON.stringify(process.env[match]),
    ],
    // Example of "supporting" a blade-like syntax:
    [/@if\s*\((.*?)\)$/gim, '{#if $1}'],
    [/@elseif\s*\((.*?)\)$/gim, '{:else if $1}'],
    [/@else$/gim, '{:else}'],
    [/@endif$/gim, '{/if}'],
    [/@each\s*\((.*?)\)$/gim, '{#each $1}'],
    [/@endeach$/gim, '{/each}'],
    [/@await\s*\((.*?)\)$/gim, '{#await $1}'],
    [/@then\s*(?:\((.*?)\))?$/gim, '{:then $1}'],
    [/@catch\s*(?:\((.*?)\))?$/gim, '{:catch $1}'],
    [/@endawait$/gim, '{/await}'],
    [/@debug\s*\((.*?)\)$/gim, '{@debug $1}'],
    [/@html\s*\((.*?)\)$/gim, '{@html $1}'],
  ],

  /** Configure globalStyle source map options */
  globalStyle: {
    sourceMap: true,
  },
};

svelte.preprocess(input, sveltePreprocess(options));

Specifics and limitations

scss/sass

The SCSS/SASS processor accepts the default sass options alongside two other props:

  • data: string - a string prepended to every scss file processed.
  • renderSync: boolean - if true, use the sync render method which is faster for dart sass.
  • implementation: object - pass the module to use to compile sass, if unspecified, svelte-preprocess will first look for node-sass and then for sass.

typescript

Since typescript is not officially supported by svelte for its template language, svelte-preprocess only type checks code in the <script></script> tag.

The following compiler options are not supported:

  • noUnusedLocals
  • noEmitOnError
  • declarations

pug

Template blocks

Some of Svelte's template syntax is invalid in pug. svelte-preprocess provides some pug mixins to represent svelte's {#...}{/...} blocks: +if(), +else(), +elseif(), +each(), +await(), +then(), +catch(), +debug().

ul
  +if('posts && posts.length > 1')
    +each('posts as post')
      li
        a(rel="prefetch" href="blog/{post.slug}") {post.title}
    +else()
      span No posts :c

Element attributes

Pug encodes everything inside an element attribute to html entities, so attr="{foo && bar}" becomes attr="foo &amp;&amp; bar". To prevent this from happening, instead of using the = operator use != which won't encode your attribute value:

button(disabled!="{foo && bar}")

Svelte Element directives

Syntax for use Svelte Element directives with Pug

input(bind:value="{foo}")
input(on:input="{bar}")

coffeescript

Safety wrapper

Since coffeescript transpiles variables to var definitions, it uses a safety mechanism to prevent variables from bleeding to outside contexts. This mechanism consists of wrapping your coffeescript code inside an IIFE which, unfortunately, prevents svelte from finding your variables. To bypass this behavior, svelte-preprocess sets the bare coffeescript compiler option to true.

FAQ

My VS Code is displaying a lot of errors on my templates when I try to use x...

image

If you have configured svelte-preprocess to use some kind of preprocessor and svelte-vscode is displaying errors like it's ignoring your preprocess configuration, that's happening because svelte-vscode needs to know how to preprocess your components. svelte-vscode works by having a svelte compiler running on the background and you can configure it by creating a svelte.config.js file on your project's root. Please check this document With Svelte VS Code section.

My typescript compilation is sloooooooow

If you have a medium-to-big project, the typescript processor might start to get slow. If you already have an IDE type checking your code, you can speed up the transpilation process by setting transpileOnly to true:

import preprocess from 'svelte-preprocess'
...
{
  ...svelteOptions,
  preprocess: preprocess({
    typescript: {
      // skips type checking
      transpileOnly: true,
      compilerOptions: {
        ...
      },
    },
  })
}
...

Warning: If you do this, you can't import types or interfaces into your svelte component without using the new TS 3.8 type import modifier: import type { SomeInterface } from './MyModule.ts' otherwise Rollup (and possibly others) will complain that the name is not exported by MyModule)

svelte-preprocess's People

Contributors

kaisermann avatar illright avatar cweili avatar joelmukuthu avatar antony avatar bastienrobert avatar benmccann avatar elliotwaite avatar fatmirsukaliq avatar igoradamenko avatar jamesbirtles avatar jgelens avatar leonidaz avatar mrkishi avatar simon-ohara avatar mon53r avatar frank3stein avatar halfnelson avatar jvmccarthy avatar tienpv222 avatar wmzy avatar wongjn avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.