UNPKG

4.52 kBJavaScriptView Raw
1const path = require('path');
2const fs = require('fs');
3const { resolve } = require('resolve.exports');
4const { createFilter } = require('@rollup/pluginutils');
5const { compile, preprocess, VERSION } = require('svelte/compiler');
6
7const PREFIX = '[rollup-plugin-svelte]';
8
9const plugin_options = new Set([
10 'emitCss',
11 'exclude',
12 'extensions',
13 'include',
14 'onwarn',
15 'preprocess',
16]);
17
18let warned = false;
19
20/**
21 * @param [options] {Partial<import('.').Options>}
22 * @returns {import('rollup').Plugin}
23 */
24module.exports = function (options = {}) {
25 const { compilerOptions = {}, ...rest } = options;
26 const extensions = rest.extensions || ['.svelte'];
27 const filter = createFilter(rest.include, rest.exclude);
28
29 if (VERSION[0] === '3') {
30 compilerOptions.format = 'esm';
31 }
32
33 for (const key in rest) {
34 if (plugin_options.has(key)) continue;
35 console.warn(
36 `${PREFIX} Unknown "${key}" option. Please use "compilerOptions" for any Svelte compiler configuration.`
37 );
38 }
39
40 // [filename]:[chunk]
41 const cache_emit = new Map();
42 const { onwarn, emitCss = true } = rest;
43
44 if (emitCss) {
45 if (compilerOptions.css) {
46 console.warn(
47 `${PREFIX} Forcing \`"compilerOptions.css": false\` because "emitCss" was truthy.`
48 );
49 }
50 compilerOptions.css = false;
51 }
52
53 return {
54 name: 'svelte',
55
56 /**
57 * Resolve an import's full filepath.
58 */
59 async resolveId(importee, importer, options) {
60 if (cache_emit.has(importee)) return importee;
61 if (!importer || importee[0] === '.' || importee[0] === '\0' || path.isAbsolute(importee))
62 return null;
63
64 // if this is a bare import, see if there's a valid pkg.svelte
65 const parts = importee.split('/');
66
67 let name = parts.shift();
68 if (name && name[0] === '@') {
69 name += `/${parts.shift()}`;
70 }
71
72 const entry = parts.join('/') || '.';
73
74 let pkg;
75 let dir;
76
77 let search_dir = importer;
78 while (search_dir !== (search_dir = path.dirname(search_dir))) {
79 dir = path.join(search_dir, 'node_modules', name);
80 const file = path.join(dir, 'package.json');
81 if (fs.existsSync(file)) {
82 pkg = JSON.parse(fs.readFileSync(file, 'utf-8'));
83 break;
84 }
85 }
86
87 if (!pkg) return;
88
89 // resolve pkg.svelte first for backwards compatibility
90 // we should resolve it after exports longer-term
91 if (entry === '.' && pkg.svelte) {
92 return path.resolve(dir, pkg.svelte);
93 }
94
95 const resolved = await this.resolve(importee, importer, { skipSelf: true, ...options });
96
97 // if we can't resolve this import without the `svelte` condition, warn the user
98 if (!resolved) {
99 try {
100 resolve(pkg, entry, { conditions: ['svelte'] });
101
102 if (!warned) {
103 console.error(
104 '\n\u001B[1m\u001B[31mWARNING: Your @rollup/plugin-node-resolve configuration\'s \'exportConditions\' array should include \'svelte\'. See https://github.com/sveltejs/rollup-plugin-svelte#svelte-exports-condition for more information\u001B[39m\u001B[22m\n'
105 );
106 warned = true;
107 }
108 } catch (e) {
109 // do nothing, this isn't a Svelte library
110 }
111 }
112 },
113
114 /**
115 * Returns CSS contents for a file, if ours
116 */
117 load(id) {
118 return cache_emit.get(id) || null;
119 },
120
121 /**
122 * Transforms a `.svelte` file into a `.js` file.
123 * NOTE: If `emitCss`, append static `import` to virtual CSS file.
124 */
125 async transform(code, id) {
126 if (!filter(id)) return null;
127
128 const extension = path.extname(id);
129 if (!~extensions.indexOf(extension)) return null;
130
131 const dependencies = [];
132 const filename = path.relative(process.cwd(), id);
133 const svelte_options = { ...compilerOptions, filename };
134
135 if (rest.preprocess) {
136 const processed = await preprocess(code, rest.preprocess, { filename });
137 if (processed.dependencies) dependencies.push(...processed.dependencies);
138 if (processed.map) svelte_options.sourcemap = processed.map;
139 code = processed.code;
140 }
141
142 const compiled = compile(code, svelte_options);
143
144 (compiled.warnings || []).forEach((warning) => {
145 if (!emitCss && warning.code === 'css-unused-selector') return;
146 if (onwarn) onwarn(warning, this.warn);
147 else this.warn(warning);
148 });
149
150 if (emitCss && compiled.css.code) {
151 const fname = id.replace(new RegExp(`\\${extension}$`), '.css');
152 compiled.js.code += `\nimport ${JSON.stringify(fname)};\n`;
153 cache_emit.set(fname, compiled.css);
154 }
155
156 if (this.addWatchFile) {
157 dependencies.forEach(this.addWatchFile);
158 } else {
159 compiled.js.dependencies = dependencies;
160 }
161
162 return compiled.js;
163 },
164 };
165};