From 00a1cb5fc6b55d9ff498336c035e6f25da6c2c15 Mon Sep 17 00:00:00 2001 From: Janos Hrubos <33330538+janoshrubos@users.noreply.github.com> Date: Mon, 23 Nov 2020 18:13:05 +0100 Subject: [PATCH] feat: svelte config (#9061) * wip: svelte webpack5 * added project svelte config * svelte snapshot --- .../__snapshots__/svelte.spec.ts.snap | 480 ++++++++++++++++++ .../__tests__/configuration/svelte.spec.ts | 17 + packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/svelte.ts | 61 ++- 4 files changed, 556 insertions(+), 3 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/svelte.spec.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap new file mode 100644 index 000000000..a828059ee --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -0,0 +1,480 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`svelte configuration for android 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': 'appFullPath', + '@': 'appFullPath', + svelte: 'svelte-native' + }, + extensions: [ + '.android.svelte', + '.svelte', + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ }, + appendTsSuffixTo: [ + '\\\\\\\\.svelte$' + ] + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('svelte') */ + { + test: /\\\\.svelte$/, + use: [ + /* config.module.rule('svelte').use('svelte-loader-hot') */ + { + loader: 'svelte-loader-hot', + options: { + dev: false, + preprocess: [ + undefined, + { + markup: function () { /* omitted long function */ } + } + ], + hotReload: false, + hotOptions: { + injectCss: false, + 'native': true + } + } + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/android/app/src/main/assets/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + 'src/app.js' + ] + } +}" +`; + +exports[`svelte configuration for ios 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/__jest__/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': 'appFullPath', + '@': 'appFullPath', + svelte: 'svelte-native' + }, + extensions: [ + '.ios.svelte', + '.svelte', + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ }, + appendTsSuffixTo: [ + '\\\\\\\\.svelte$' + ] + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('svelte') */ + { + test: /\\\\.svelte$/, + use: [ + /* config.module.rule('svelte').use('svelte-loader-hot') */ + { + loader: 'svelte-loader-hot', + options: { + dev: false, + preprocess: [ + undefined, + { + markup: function () { /* omitted long function */ } + } + ], + hotReload: false, + hotOptions: { + injectCss: false, + 'native': true + } + } + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/ios/__jest__/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + 'src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts new file mode 100644 index 000000000..c89102aa3 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -0,0 +1,17 @@ +// @ts-ignore +import Config from 'webpack-chain'; +import svelte from '../../src/configuration/svelte'; +import { init } from '../../src'; + +describe.only('svelte configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + init({ + [platform]: true, + }); + expect(svelte(new Config()).toString()).toMatchSnapshot(); + }); + } +}); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index caa0482b0..691dc74b3 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -31,6 +31,7 @@ "sass": "^1.29.0", "sass-loader": "^10.1.0", "source-map": "^0.7.3", + "svelte-native-preprocessor": "^0.2.0", "terser-webpack-plugin": "^5.0.3", "ts-dedent": "^2.0.0", "ts-loader": "^8.0.11", diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index cbc9e8619..faf1e683c 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -1,10 +1,65 @@ import base from './base'; -import { IWebpackEnv } from '@nativescript/webpack'; +import { env as _env, IWebpackEnv } from '../index'; import Config from 'webpack-chain'; +import { getPlatform, getProjectRootPath } from '../helpers/project'; +import { merge } from 'webpack-merge'; +import svelteNativePreprocessor from 'svelte-native-preprocessor'; -// todo: add base configuration for svelte -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); + const platform = getPlatform(); + const mode = env.production ? 'production' : 'development'; + const production = mode === 'production'; + + // resolve .svelte files + // the order is reversed because we are using prepend! + config.resolve.extensions.prepend('.svelte').prepend(`.${platform}.svelte`); + + // add a rule for .svelte files + config.module + .rule('svelte') + .test(/\.svelte$/) + .use('svelte-loader-hot') + .loader('svelte-loader-hot') + .tap((options) => { + return { + ...options, + dev: production, + preprocess: [getSvelteConfig()?.preprocess, svelteNativePreprocessor()], + hotReload: production, + hotOptions: { + injectCss: false, + native: true, + }, + }; + }) + .end(); + + // set up ts support in svelte files + config.module + .rule('ts') + .use('ts-loader') + .loader('ts-loader') + .tap((options = {}) => { + return merge(options, { + appendTsSuffixTo: ['\\.svelte$'], + }); + }); + + // add an alias for svelte, since some plugins may try to import it + config.resolve.alias.set('svelte', 'svelte-native'); + return config; } + +function getSvelteConfig(): { preprocess: any } | null { + try { + const resolvedPath = require.resolve(`./svelte.config.js`, { + paths: [getProjectRootPath()], + }); + return require(resolvedPath); + } catch (e) { + return null; + } +}