This my first time running a Svelte app and I have this issue where the app doesn't seem to know where build/build.css and build/build.js are.
I got the same issue when I tried Svelte with Tailwind.
This is my config when I created the project:
import svelte from 'rollup-plugin-svelte';
import commonjs from '#rollup/plugin-commonjs';
import resolve from '#rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import css from 'rollup-plugin-css-only';
const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
svelte({
compilerOptions: {
// enable run-time checks when not in production
dev: !production
}
}),
// we'll extract any component CSS out into
// a separate file - better for performance
css({ output: 'bundle.css' }),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
This is the ouput after running npm start:
Here is my folder structure:
What went wrong?
This looks very much like the official Svelte template. In this case, the command to build, watch, & serve is npm run dev.
npm start just runs the web server and serve existing files. You'd use it, for example to test your prod build after npm run build.
Related
I tried to move from vue-cli to vite but observed some obstacles.
I want to include several npm packages into my vue 3 project.
I tried to understand the issue, and basically the error came when I imported
https://www.npmjs.com/package/rdf-parse
If I run npm run dev everything works as expected, but when I run npm run build and serve the dist folder with http-server the error:
Uncaught TypeError: Object.defineProperty called on non-object at Function.defineProperty
occurs.
The code worked with vue-cli and in vite-dev mode so I expect I missed somethin crucial in the vite.config.js
But I didnt find anything in the docu that helped me out and also no thread here on stackoverflow or elsewhere.
I created a repo with a minimal example here: https://github.com/stackoverflowuser/vite-issue
It is the npm vue3 template (npm init vue#3) and only the library rdf-parse is added.
// vite.config.js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
import { NodeModulesPolyfillPlugin } from '#esbuild-plugins/node-modules-polyfill'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url)),
}
},
build: {
target: "es2020"
},
optimizeDeps: {
esbuildOptions: {
// Limit target browsers due to issue: Big integer literals are not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari13" + 2 overrides)'
target: "es2020",
// Node.js global to browser globalThis
define: {
global: 'globalThis'
},
// Enable esbuild polyfill plugins
plugins: [
NodeModulesPolyfillPlugin()
]
}
},
})
In hope someone can give me a hint.
I have a web app created with create-react-app that I am trying to migrate to vite, but it is not working when I build with vite build --minify false.
Everything works well on vite dev version.
Vite 2.9.9,
react: 16.13.1
vite.config.js
import { defineConfig, loadEnv } from 'vite'
import svgr from 'vite-plugin-svgr'
import process from 'process'
import react from '#vitejs/plugin-react'
export default defineConfig(({ command, mode }) => {
// Load env file based on `mode` in the current working directory
const env = loadEnv(mode, process.cwd())
return {
plugins: [
react(),
svgr({
exportAsDefault: false,
// A minimatch pattern, or array of patterns, which specifies the files in the build the plugin should include. By default all svg files will be included.
include: '**/*.svg',
}),
],
build: {
commonjsOptions: {
strictRequires: true,
// transformMixedEsModules: true,
}
}
}
})
Error:
require is not defined on js-cookie (coming from an okta-auth-js dependency).
Research tells me that require should not be used in the browser. So I tried the following option.
I have tried to add in transformMixedEsModules: true to the build options, but that changes the error to:
index.6cd5b200.js:108281 Uncaught TypeError: _typeof$3 is not a function
at _interopRequireWildcard$T (index.6cd5b200.js:108281:23)
at index.6cd5b200.js:108267:1
Am I missing a plugin or something?
Background:
I have a Webpack setup that I use to preprocess SCSS with PurgeCSS with a live HMR server with esbuild-loader for speeding up compiles in Webpack but even then my compile times are still slow and I would like the raw-speed of ESBuild and remove Webpack setup altogether.
The basic setup of ESBuild is easy, you install esbuild using npm and add the following code in your package.json:
{
...
"scripts": {
...
"watch": "esbuild --bundle src/script.js --outfile=dist/script.js --watch"
},
...
}
and run it by using the following command:
npm run watch
This single-line configuration will bundle your scripts and styles (you can import style.css in script.js) and output the files in the dist directory but this doesn't allow advance configuration for ESBuild like outputting a different name for your stylesheet and script files or using plugins.
Problems:
How to configure ESBuild using an external config file?
ESBuild doesn't support SCSS out-of-the-box. How to configure external plugins like esbuild-sass-plugin and to go even further, how to setup PostCSS and its plugins like Autoprefixer?
How to setup dev server with auto-rebuild?
How to setup PurgeCSS?
Solutions:
1. How to configure ESBuild using an external config file?
Create a new file in root: esbuild.js with the following contents:
import esbuild from "esbuild";
esbuild
.build({
entryPoints: ["src/styles/style.css", "src/scripts/script.js"],
outdir: "dist",
bundle: true,
plugins: [],
})
.then(() => console.log("⚡ Build complete! ⚡"))
.catch(() => process.exit(1));
Add the following code in your package.json:
{
...
"scripts": {
...
"build": "node esbuild.js"
},
...
}
Run the build by using npm run build command and this would bundle up your stylesheets and scripts and output them in dist directory.
For more details and/or adding custom build options, please refer to ESBuild's Build API documentation.
2. ESBuild doesn't support SCSS out-of-the-box. How to configure external plugins like esbuild-sass-plugin and to go even further, how to setup PostCSS and plugins like Autoprefixer?
Install npm dependencies: npm i -D esbuild-sass-plugin postcss autoprefixer
Edit your esbuild.js to the following code:
import esbuild from "esbuild";
import { sassPlugin } from "esbuild-sass-plugin";
import postcss from 'postcss';
import autoprefixer from 'autoprefixer';
// Generate CSS/JS Builds
esbuild
.build({
entryPoints: ["src/styles/style.scss", "src/scripts/script.js"],
outdir: "dist",
bundle: true,
metafile: true,
plugins: [
sassPlugin({
async transform(source) {
const { css } = await postcss([autoprefixer]).process(source);
return css;
},
}),
],
})
.then(() => console.log("⚡ Build complete! ⚡"))
.catch(() => process.exit(1));
3. How to setup dev server with auto-rebuild?
ESBuild has a limitation on this end, you can either pass in watch: true or run its server. It doesn't allow both.
ESBuild also has another limitation, it doesn't have HMR support like Webpack does.
So to live with both limitations and still allowing a server, we can use Live Server. Install it using npm i -D #compodoc/live-server.
Create a new file in root: esbuild_watch.js with the following contents:
import liveServer from '#compodoc/live-server';
import esbuild from 'esbuild';
import { sassPlugin } from 'esbuild-sass-plugin';
import postcss from 'postcss';
import autoprefixer from 'autoprefixer';
// Turn on LiveServer on http://localhost:7000
liveServer.start({
port: 7000,
host: 'localhost',
root: '',
open: true,
ignore: 'node_modules',
wait: 0,
});
// Generate CSS/JS Builds
esbuild
.build({
logLevel: 'debug',
metafile: true,
entryPoints: ['src/styles/style.scss', 'src/scripts/script.js'],
outdir: 'dist',
bundle: true,
watch: true,
plugins: [
sassPlugin({
async transform(source) {
const { css } = await postcss([autoprefixer]).process(
source
);
return css;
},
}),
],
})
.then(() => console.log('⚡ Styles & Scripts Compiled! ⚡ '))
.catch(() => process.exit(1));
Edit the scripts in your package.json:
{
...
"scripts": {
...
"build": "node esbuild.js",
"watch": "node esbuild_watch.js"
},
...
}
To run build use this command npm run build.
To run dev server with auto-rebuild run npm run watch. This is a "hacky" way to do things but does a fair-enough job.
4. How to setup PurgeCSS?
I found a great plugin for this: esbuild-plugin-purgecss by peteryuan but it wasn't allowing an option to be passed for the html/views paths that need to be parsed so I
created esbuild-plugin-purgecss-2 that does the job. To set it up, read below:
Install dependencies npm i -D esbuild-plugin-purgecss-2 glob-all.
Add the following code to your esbuild.js and esbuild_watch.js files:
// Import Dependencies
import glob from 'glob-all';
import purgecssPlugin2 from 'esbuild-plugin-purgecss-2';
esbuild
.build({
plugins: [
...
purgecssPlugin2({
content: glob.sync([
// Customize the following URLs to match your setup
'./*.html',
'./views/**/*.html'
]),
}),
],
})
...
Now running the npm run build or npm run watch will purgeCSS from the file paths mentioned in glob.sync([...] in the code above.
TL;DR:
Create an external config file in root esbuild.js and add the command to run it in package.json inside scripts: {..} e.g. "build": "node esbuild.js" to reference and run the config file by using npm run build.
ESBuild doesn't support HMR. Also, you can either watch or serve with ESBuild, not both. To overcome, use a separate dev server library like Live Server.
For the complete setup, please refer to my custom-esbuild-with-scss-purgecss-and-liveserver repository on github.
Final Notes:
I know this is a long thread but it took me a lot of time to figure these out. My intention is to have this here for others looking into the same problems and trying to figure out where to get started.
Thanks.
Adding to Arslan's terrific answer, you can use the PurgeCSS plug-in for postcss to totally eliminate Step 4.
First, install the postcss-purgecss package: npm install #fullhuman/postcss-purgecss
Then, replace the code from Step 2 in Arslan's answer with the code shown below (which eliminates the need for Step 4).
import esbuild from "esbuild";
import { sassPlugin } from "esbuild-sass-plugin";
import postcss from "postcss";
import autoprefixer from "autoprefixer";
import purgecss from "#fullhuman/postcss-purgecss";
// Generate CSS/JS Builds
esbuild
.build({
entryPoints: [
"roomflows/static/sass/project.scss",
"roomflows/static/js/project.js",
],
outdir: "dist",
bundle: true,
loader: {
".png": "dataurl",
".woff": "dataurl",
".woff2": "dataurl",
".eot": "dataurl",
".ttf": "dataurl",
".svg": "dataurl",
},
plugins: [
sassPlugin({
async transform(source) {
const { css } = await postcss([
purgecss({
content: ["roomflows/templates/**/*.html"],
}),
autoprefixer,
]).process(source, {
from: "roomflows/static/sass/project.scss",
});
return css;
},
}),
],
minify: true,
metafile: true,
sourcemap: true,
})
.then(() => console.log("⚡ Build complete! ⚡"))
.catch(() => process.exit(1));
The problem
I'm building Sapper SSR app that loads content from Firebase storage based on data required from Firebase realtime database. My app is deployed on Firebase cloud functions. But last time I deployed I got this error, since last deploy I implemented loading some data from realtime database and other minor features, so I don't know what is causing this error.
Deploy command:
/usr/bin/node /usr/local/lib/node_modules/npm/bin/npm-cli.js run deploy:functions --scripts-prepend-node-path=auto
> violette-website#0.0.1 deploy:functions /home/hejtmus/Documents/Websites/Violette/sapper/Violette/functions
> firebase deploy --only functions:ssr
=== Deploying to 'violette-77756'...
i deploying functions
i functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i functions: ensuring required API cloudbuild.googleapis.com is enabled...
✔ functions: required API cloudbuild.googleapis.com is enabled
✔ functions: required API cloudfunctions.googleapis.com is enabled
i functions: preparing functions directory for uploading...
i functions: packaged functions (4.41 MB) for uploading
✔ functions: functions folder uploaded successfully
i functions: current functions in project: ssr(us-central1)
i functions: uploading functions in project: ssr(us-central1)
i functions: updating Node.js 12 function ssr(us-central1)...
⚠ functions[ssr(us-central1)]: Deployment error.
Function failed on loading user code. Error message: Error: please examine your function logs to see the error cause: https://cloud.google.com/functions/docs/monitoring/logging#viewing_logs
Functions deploy had errors with the following functions:
ssr
To try redeploying those functions, run:
firebase deploy --only "functions:ssr"
To continue deploying other features (such as database), run:
firebase deploy --except functions
Error: Functions did not deploy properly.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! violette-website#0.0.1 deploy:functions: `firebase deploy --only functions:ssr`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the violette-website#0.0.1 deploy:functions script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/hejtmus/.npm/_logs/2020-09-27T18_34_13_296Z-debug.log
Process finished with exit code 1
Firebase logs:
Error: function terminated. Recommended action: inspect logs for termination reason. Function cannot be initialized.
{"#type":"type.googleapis.com/google.cloud.audit.AuditLog","status":{"code":3,"message":"Function failed on loading user code. Error message: Error: please examine your function logs to see the error cause: https://cloud.google.com/functions/docs/monitoring/logging#viewing_logs"},"authenticationInfo":{"principalEmail":"filip.holcik.official#gmail.com"},"serviceName":"cloudfunctions.googleapis.com","methodName":"google.cloud.functions.v1.CloudFunctionsService.UpdateFunction","resourceName":"projects/violette-77756/locations/us-central1/functions/ssr"}
What I tried
I tried:
running app in dev mode, works perfect
building app as js function, works perfect
serving app via firebase serve, works perfect
deploying app using firebase deploy or firebase deploy --only functions, none of them works, throws above specified error
checking code for errors and misconfiguration, found nothing
I tried solving this problem with knowledge from this article, I followed this tutorial form step to step, but I still got the same error:
https://blog.logrocket.com/build-an-ssr-web-app-with-firebase-functions-hosting-and-svelte-sapper/
I tried also removing code I added and deployng app without loading data from firebase realtime database, but it didn't help.
Code:
index.js (cloud functions):
const functions = require('firebase-functions');
const { sapperServer } = require('./__sapper__/build/server/server');
exports.ssr = functions.https.onRequest(sapperServer);
server.js:
import sirv from 'sirv';
import express from 'express';
import compression from 'compression';
import * as sapper from '#sapper/server';
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
const sapperServer = express()
.use(
compression({ threshold: 0 }),
sirv(`static`, { dev }),
sapper.middleware()
)
if(dev){
sapperServer.listen(PORT, err => {
if (err) console.log('error', err);
});
}
export { sapperServer }
I will provide more info if needed.
What was the problem
The problem was, that I used firebase for browser, Svelte is compiler an it runs in Node.js environment, it has to be bundled by code bundler (I use rollup). To be able to run firebase in node, just specify mainFields in rollup configuration.
resolve({
browser: true,
dedupe: ['svelte'],
mainFields: ['main']
}),
I use firebase only in client, so there is no need to specify mainFields parameter in server in my case.
Full rollup configuration
import resolve from '#rollup/plugin-node-resolve';
import replace from '#rollup/plugin-replace';
import commonjs from '#rollup/plugin-commonjs';
import svelte from 'rollup-plugin-svelte';
import postcss from 'rollup-plugin-postcss';
import autoPreprocess from "svelte-preprocess";
import pluginJson from "#rollup/plugin-json";
import babel from 'rollup-plugin-babel';
import { terser } from 'rollup-plugin-terser';
import config from 'sapper/config/rollup.js';
import pkg from './package.json';
const mode = process.env.NODE_ENV;
const dev = mode === 'development';
const legacy = !!process.env.SAPPER_LEGACY_BUILD;
const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]#sapper[/\\]/.test(warning.message)) || onwarn(warning);
const preprocessOptions = {
postcss: {
plugins: [
require('postcss-import'),
require('postcss-preset-env')({
stage: 0,
browsers: 'last 2 versions',
autoprefixer: { grid: true }
})
]
}
};
export default {
client: {
input: config.client.input(),
output: config.client.output(),
plugins: [
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode)
}),
svelte({
preprocess: autoPreprocess(preprocessOptions),
dev,
hydratable: true,
emitCss: true,
css: css => {
css.write('static/css/bundle.css');
}
}),
postcss({
extract: "static/css/imported.min.css",
sourceMap: true,
minimize: true,
}),
resolve({
browser: true,
dedupe: ['svelte'],
mainFields: ['main']
}),
commonjs(),
legacy && babel({
extensions: ['.js', '.mjs', '.html', '.svelte'],
runtimeHelpers: true,
exclude: ['node_modules/#babel/**'],
presets: [
['#babel/preset-env', {
targets: '> 0.25%, not dead'
}]
],
plugins: [
'#babel/plugin-syntax-dynamic-import',
['#babel/plugin-transform-runtime', {
useESModules: true
}]
]
}),
!dev && terser({
module: true
})
],
onwarn,
},
server: {
input: config.server.input(),
output: config.server.output(),
plugins: [
replace({
'process.browser': false,
'process.env.NODE_ENV': JSON.stringify(mode)
}),
svelte({
preprocess: autoPreprocess(preprocessOptions),
generate: 'ssr',
dev,
css: css => {
css.write('static/css/bundle.css');
}
}),
postcss({
extract: "static/css/imported.min.css",
sourceMap: true,
minimize: true,
}),
resolve({
dedupe: ['svelte']
}),
commonjs(),
pluginJson(),
],
external: Object.keys(pkg.dependencies).concat(
require('module').builtinModules || Object.keys(process.binding('natives'))
),
onwarn,
},
serviceworker: {
input: config.serviceworker.input(),
output: config.serviceworker.output(),
plugins: [
resolve(),
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode)
}),
commonjs(),
!dev && terser()
],
onwarn,
}
};
I have project which uses lerna ( monorepo, multiple packages ). Few of the packages are standalone apps.
What I want to achieve is having aliases on few of the packages to have something like dependency injection. So for example I have alias #package1/backendProvider/useCheckout and in webpack in my standalone app I resolve it as ../../API/REST/useCheckout . So when I change backend provider to something else I would only change it in webpack.
Problem
Problem appears when this alias is used by some other package ( not standalone app ). For example:
Directory structure looks like this:
Project
packageA
ComponentA
packageB
API
REST
useCheckout
standalone app
ComponentA is in packageA
useCheckout is in packageB under /API/REST/useCheckout path
ComponentA uses useCheckout with alias like import useCheckout from '#packageA/backendProvider/useCheckout
Standalone app uses componentA
The error I get is that Module not found: Can't resolve '#packageA/backendProvider/useCheckout
However when same alias is used in standalone app ( that has webpack with config provided below ) it is working. Problem occurs only for dependencies.
Potential solutions
I know that one solution would be to compile each package with webpack - but that doesn't really seem friendly. What I think is doable is to tell webpack to resolve those aliases to directory paths and then to recompile it. First part ( resolving aliases ) is done.
Current code
As I'm using NextJS my webpack config looks like this:
webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
// Fixes npm packages that depend on `fs` module
config.node = {
fs: "empty"
};
const aliases = {
...
"#package1/backendProvider": "../../API/REST/"
};
Object.keys(aliases).forEach(alias => {
config.module.rules.push({
test: /\.(js|jsx)$/,
include: [path.resolve(__dirname, aliases[alias])],
use: [defaultLoaders.babel]
});
config.resolve.alias[alias] = path.resolve(__dirname, aliases[alias]);
});
return config;
}
You don’t need to use aliases. I have a similar setup, just switch to yarn (v1) workspaces which does a pretty smart trick, it adds sym link to all of your packages in the root node_modules.
This way, each package can import other packages without any issue.
In order to apply yarn workspaces with lerna:
// lerna.json
{
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/**"
],
}
// package.json
{
...
"private": true,
"workspaces": [
"packages/*",
]
...
}
This will enable yarn workspace with lerna.
The only think that remains to solve is to make consumer package to transpile the required package (since default configs of babel & webpack is to ignore node_module transpilation).
In Next.js project it is easy, use next-transpile-modules.
// next.config.js
const withTM = require('next-transpile-modules')(['somemodule', 'and-another']); // pass the modules you would like to see transpiled
module.exports = withTM();
In other packages that are using webpack you will need to instruct webpack to transpile your consumed packages (lets assume that they are under npm scope of #somescope/).
So for example, in order to transpile typescript, you can add additional module loader.
// webpack.config.js
{
...
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
include: /[\\/]node_modules[\\/]#somescope[\\/]/, // <-- instruct to transpile ts files from this path
options: {
allowTsInNodeModules: true, // <- this a specific option of ts-loader
transpileOnly: isDevelopment,
compilerOptions: {
module: 'commonjs',
noEmit: false,
},
},
}
]
}
...
resolve: {
symlinks: false, // <-- important
}
}
If you have css, you will need add a section for css as well.
Hope this helps.
Bonus advantage, yarn workspaces will reduce your node_modules size since it will install duplicate packages (with the same semver version) once!