I like using Tailwind CSS in my React and Laravel projects.
Now I've started learning NestJS and I want to use Tailwind CSS in my project, but I couldn't.
Since I couldn't find any results on Google, I'm asking you guys.
I would be grateful for any resource or your detailed answer.
The current state of my project is as follows. I don't know where I went wrong, TailwindCSS is not working.
Please note that I am just starting to learn NestJS.
main.ts
import { NestFactory } from '#nestjs/core';
import { NestExpressApplication } from '#nestjs/platform-express';
import { join } from 'path';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.useStaticAssets(join(__dirname, '..', 'public'));
app.setBaseViewsDir(join(__dirname, '..', 'views'));
app.setViewEngine('hbs');
await app.listen(3000);
console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();
app.controller.ts
import { Controller, Get, Render } from '#nestjs/common';
#Controller()
export class AppController {
#Get()
#Render('index')
root() {
return { message: 'Hello world!' };
}
}
app.module.ts
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
#Module({
imports: [],
controllers: [AppController],
providers: [],
})
export class AppModule {}
tailwind.config.js
module.exports = {
content: ['./views/*.hbs', './views/**/*.hbs'],
theme: {
extend: {},
},
plugins: [],
};
webpack-hmr.config.js
const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');
module.exports = function (options, webpack) {
return {
...options,
//entry: ['webpack/hot/poll?100', options.entry],
entry: './src/main.ts',
externals: [
nodeExternals({
allowlist: ['webpack/hot/poll?100'],
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
},
},
],
},
{
test: /\.ts$/,
use: [{ loader: 'ts-loader' }],
},
],
},
plugins: [
...options.plugins,
new webpack.HotModuleReplacementPlugin(),
new webpack.WatchIgnorePlugin({
paths: [/\.js$/, /\.d\.ts$/],
}),
new RunScriptWebpackPlugin({ name: options.output.filename }),
],
};
};
index.hbs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>NestJS App With TailwindCSS</title>
<link rel="stylesheet" href="/assets/css/tailwind.css">
</head>
<body>
<header class="w-full px-8 text-gray-700 bg-white flex">
<h1 class="bg-slate-200">
{{ message }}
</h1>
</header>
</body>
</html>
and script command
"start:dev": "nest build --webpack --webpackPath webpack-hmr.config.js --watch",
Related
I'm trying to use ModelsService from ModelsModule in AppService from AppModule.
In development mode, everything works ok. But on production mode I'm getting an error:
[Nest] 16460 - 03/13/2021, 11:14:00 PM [ExceptionsHandler] this.modelsService.countOnlineModels is not a function +1136ms
TypeError: this.modelsService.countOnlineModels is not a function
at _.createAppStore (/Users/egor.kamenev/Desktop/camoncam/dist/static/server/serverBundle.js:1:76579)
app.service.tsx
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { createStore, Store } from 'redux';
import { Provider } from 'react-redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { Inject, Injectable, forwardRef } from '#nestjs/common';
import { ModelsService } from './models/models.service';
import App from '../client/components/app/app';
import reducers from '../client/store/reducers';
import epics from '../client/store/epics';
import History from '../client/components/router/history';
import _merge from 'lodash/merge';
#Injectable()
export class AppService {
constructor(
#Inject(forwardRef(() => ModelsService))
private readonly modelsService: ModelsService,
) {}
async createAppStore(
cookies: Record<string, string>,
params: string,
): Promise<Store> {
const calculatedState: CommonStateType = {
main: _merge({}, initState.main, {
onlineModelsCount: await this.modelsService.countOnlineModels(),
allModelsCount: await this.modelsService.countAllModels(),
}),
};
return createStore(
reducers,
calculatedState,
composeWithDevTools(...epics),
);
}
}
app.module.ts
import { TypeOrmModule } from '#nestjs/typeorm';
import { Module } from '#nestjs/common';
import { join } from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ModelsModule } from './models/models.module';
import { ServeStaticModule } from '#nestjs/serve-static';
import { Models } from './models/schemas/modelTable.entity';
import { serverConfig } from './configs/appConfig';
#Module({
imports: [
ModelsModule,
ServeStaticModule.forRoot({
rootPath: join(__dirname, serverConfig.clientPath),
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
models.module.ts
import { Module } from '#nestjs/common';
import { ModelsService } from './models.service';
import { ModelsController } from './models.controller';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Models } from './schemas/modelTable.entity';
#Module({
imports: [TypeOrmModule.forFeature([Models])],
controllers: [ModelsController],
providers: [ModelsService],
exports: [ModelsService],
})
export class ModelsModule {}
webpack.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: "production",
entry: path.resolve(__dirname, './src/server/main.ts'),
target: 'node',
optimization: {
minimize: true,
minimizer: [
`...`,
new CssMinimizerPlugin(),
]
},
devtool: 'inline-source-map',
externals: [nodeExternals({
modulesFromFile: true,
})],
output: {
filename: 'serverBundle.js',
path: path.resolve(__dirname, 'dist/static/server'),
},
stats: 'errors-warnings',
resolve: {
modules: [__dirname, 'node_modules'],
extensions: ["css", ".ts", ".tsx", ".scss", ".js", ".json"]
},
output: {
publicPath: "/"
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css'
})
],
module: {
rules: [
{
test: /\.ts(x?)$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.scss$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]-[local]-[contenthash:base64:6]'
}
}
},
'sass-loader'
],
},
{
test: /\.svg$/,
loader: 'react-svg-loader',
options: {
classIdPrefix: '[name]-[hash:8]__',
uniqueIdPrefix: true,
}
},
{
test: /\.(png|webp|jpe?g|avif)$/i,
loader: 'file-loader',
options: {
publicPath: '/images/',
outputPath: '../client/images',
name:'[name].[contenthash].[ext]'
},
}
]
}
}
Does anyone experience this? what is the correct way to call an imported service in another module service?
The problem was with webpack minimizer. It sets the wrong class names for services.
optimization.minimizer = false
decided this problem.
Have an angular 7 application and have implemented angular universal using node and express, and then deployed to firebase.
Having an issue when trying to load pages other than the root (/), which causes the server to return the html of the root (/) rather than the page the user requests.
Not sure from where the issue is originating (Angular, Angular Universal or Firebase).
This is my index.ts:
import * as functions from 'firebase-functions';
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import {renderModuleFactory} from '#angular/platform-server';
import {enableProdMode} from '#angular/core';
import * as express from 'express';
import {readFileSync} from 'fs';
enableProdMode();
const app = express();
const indexHtml = readFileSync(__dirname + '/index-server.html', 'utf-8').toString();
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./main');
import {provideModuleMap} from '#nguniversal/module-map-ngfactory-loader';
app.engine('html', (_, options, callback) => {
// Always '/' (root path)
console.log('OPTIONS.REQ.URL', options.req.url);
renderModuleFactory(AppServerModuleNgFactory, {
// My index-server.html
document: indexHtml,
url: options.req.url,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
}).then(html => {
callback(null, html);
});
});
app.set('view engine', 'html');
app.set('views', __dirname);
app.get('*.*', express.static(__dirname + '/dist', {
maxAge: '1y'
}));
app.get('*', (req, res) => {
res.render(__dirname + '/index-server.html', {req});
});
exports.ssrApp = functions.https.onRequest(app);
This is my app-routing.module.ts:
import {RouterModule, Routes} from '#angular/router';
import {NgModule} from '#angular/core';
import {HomePageComponent} from './home-page/home-page.component';
import {ToursComponent} from './tours/tours.component';
import {MaltaComponent} from './malta/malta.component';
import {AboutComponent} from './about/about.component';
import {ContactComponent} from './contact/contact.component';
import {TourComponent} from './tours/tour/tour.component';
import {ErrorComponent} from './error/error.component';
import {BlogComponent} from './blog/blog.component';
import {BlogPageComponent} from './blog/blog-page/blog-page.component';
import {PageResolver} from './services/pages/page-resolver.service';
const AppRoutes: Routes = [
{
path: 'home',
component: HomePageComponent,
data: {
state: 'home',
pageId: 'home'
},
resolve: {
page: PageResolver
}
},
{
path: 'tours',
component: ToursComponent,
data: {
state: 'tours',
pageId: 'tours'
},
resolve: {
page: PageResolver
}
},
{
path: 'tours/:id',
component: TourComponent,
data: {
state: 'tour'
}
},
{
path: 'blog',
component: BlogComponent,
data: {
state: 'blogs',
pageId: 'blog'
},
resolve: {
page: PageResolver
}
},
{
path: 'blog/:id',
component: BlogPageComponent,
data: {
state: 'blog'
}
},
{
path: 'malta',
component: MaltaComponent,
data: {
state: 'malta',
pageId: 'malta'
},
resolve: {
page: PageResolver
}
},
{
path: 'about',
component: AboutComponent,
data: {
state: 'about',
pageId: 'about'
},
resolve: {
page: PageResolver
}
},
{
path: 'contact',
component: ContactComponent,
data: {
state: 'contact',
pageId: 'contact'
},
resolve: {
page: PageResolver
}
},
{
path: 'something-went-wrong',
component: ErrorComponent,
data: {
state: 'error',
pageId: 'error'
}
},
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
},
{
path: '**',
redirectTo: '/something-went-wrong'
}
];
#NgModule({
imports: [
RouterModule.forRoot(AppRoutes, {
useHash: true,
scrollPositionRestoration: 'enabled',
initialNavigation: 'enabled'
})
],
exports: [RouterModule]
})
export class AppRoutingModule {
}
This is my firebase.json:
{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"function": "ssrApp"
}
]
},
"functions": {
"predeploy": "npm --prefix \"$RESOURCE_DIR\" run build"
}
}
Would appreciate any help with this issue!
The issue is solved after removing useHash: true from the app-routing.module.ts.
Thanks to yeya for helping get to the solution.
Your issue is related to Browser URL styles
Based on this answer: Try change the rewrites from "function": "ssrApp" to "destination": "/index-server.html"
The requestindex-server.html will trigger the function.
I want to be able to use import in my react application for not only js/jsx files but also for css files. From what I've read, the best way to do that is to use the extract-text-webpack-plugin which will take your imported css files and bundle them together.
I've set it up so that its generating my bundled css file, but for some reason every time I load my page I get a syntax error:
SyntaxError: MyWebpage/views/global.css: Unexpected token, expected ; (1:5)
> 1 | body {
| ^
2 | margin: 0;
3 | }
My setup looks like this:
webpack.config.js
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const config = {
entry: ['babel-polyfill', './views/Index.jsx'],
output: {
path: path.resolve(__dirname, 'public'),
filename: 'bundle.js',
publicPath: '/public'
},
module: {
rules: [
{ test: /\.(jsx|js)$/, exclude: /node_modules/ , use: 'babel-loader' },
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
]
};
module.exports = config;
The entry point ./views/Index.js is where I'm importing my css file:
Index.js
import React from 'react';
import Layout from './Layout.jsx';
import PageContent from './PageContent.jsx';
import './global.css';
class Index extends React.Component {
render() {
return (
<Layout title={this.props.title}>
<PageContent />
</Layout>
);
}
}
export default Index;
Inside the imported ./Layout.jsx file I'm using a <link> to include the bundled css file in my page:
Layout.jsx
import React from 'react';
class Layout extends React.Component {
render() {
return (
<html>
<head>
<title>{this.props.title}</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root">
{this.props.children}
</div>
<script type="text/javascript" src="./bundle.js"></script>
</body>
</html>
);
}
}
export default Layout;
I'm pretty confused because it seems like my app is building fine, but when I try to access my webpage I keep getting a syntax error.
Can anyone please help me understand what I'm doing wrong?
It seems problem with loaders below is example of webpack.config.js file working for jsx and css loaders :
module.exports = {
entry: './app/index.js',
output: {
path: __dirname,
filename: 'dist/bundle.js'
},
devServer: {
inline: true,
port: 3000
},
module: {
loaders: [{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react', 'react-hmre']
}
},
{
test: /\.scss$/,
loaders: [ 'style', 'css', 'sass' ]
}]
}
};
it seems like babel or webpack is not loading the loaders.
This variant helps me with it (just include into webpack.config.js):
require.extensions['.css'] = () => {
return;
};
More here... [link]
I'm trying to create a server rendered react app, the only part I'm stuck on is importing my components to my express server and getting the static markdown to send back to the user. Essentially what I have right now is this:
Express server:
const Report = require('../public/source/components/index.js').default;
....
router.get('/*', function(req, res, next) {
var reportHTML = ReactDOMServer.renderToStaticMarkup(react.createElement(Report)))
res.render('index', { title: 'Report' });
});
When I hit that route, I get the following error:
Warning: React.createElement: type is invalid -- expected a string
(for built-in components) or a class/function (for composite components)
but got: object. You likely forgot to export your component from the file
it's defined in. Check the render method of `ReportApp`.
in ReportApp
The contents of my index.js file, note that I stripped out a lot of the complexity involving graphql and setting the initial state, which is why this isn't a functional component.
import React, { Component } from 'react';
import Header from './header/Header';
import PageOneLayout from './pageOneLayout/PageOneLayout';
import styles from './main.scss';
const hexBackground = require('./assets/hex_background.png');
export default class ReportApp extends Component {
render() {
return (
<div className={styles.contentArea}>
<img src={`/build/${hexBackground}`} alt={'hexagonal background'} className={styles.hexBackground}/>
<Header client={"client name"} />
<div className={styles.horizontalLine}></div>
<PageOneLayout chartData={this.state} />
</div>
)
}
}
Any pointers in the right direction would be appreciated!
EDIT:
here's my webpack:
/* eslint-disable no-console */
/* eslint-disable import/no-extraneous-dependencies */
import autoprefixer from 'autoprefixer';
import nodemon from 'nodemon';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
nodemon({
script: './bin/www',
ext: 'js json',
ignore: ['public/'],
});
nodemon.on('start', () => {
console.log('App has started');
}).on('quit', () => {
console.log('App has quit');
}).on('restart', files => console.log('App restarted due to: ', files));
export default {
watch: true,
entry: './public/source/main.js',
output: { path: `${__dirname}/public/build/`, filename: 'main.js' },
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-1'],
plugins: ['transform-decorators-legacy'],
cacheDirectory: true
}
},
// {
// test: /\.jsx?$/,
// exclude: /node_modules/,
// loader: 'eslint',
// },
{
test: /\.s?css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader!sass-loader?outputStyle=expanded&sourceMap')
},
{ test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$|\.wav$|\.mp3$/, loader: "file", output: {path: `${__dirname}/public/build/`, filename: 'logo.svg'}},
],
},
// eslint: {
// configFile: './public/.eslintrc',
// },
resolve: {
modulesDirectories: ['node_modules', 'public/source'],
extensions: ['', '.js', '.jsx'],
},
postcss: [
autoprefixer,
],
plugins: [
new ExtractTextPlugin('main.css', { allChunks: true }),
],
};
There are few things to consider:
Are you doing any code transpiling at server side?
How are you building your component bundle(show the config, I assume webpack)?
Make sure the bundle component exposes the component.
The extra createElement shouldn't be needed in this case ReactDOMServer.renderToStaticMarkup(react.createElement(Report))).
Whilst developing using react / webpack / node I reference other components using "import Map from './map.jsx';" or similar statements. I then webpacked to a bundle and attempted to host it on IIS along with an index.html page and the fonts folder. However in the console I get the error: Cannot find module "./map.jsx", as if it's trying to reference a local file, but I thought it was supposed to pack those into the bundle?
If there's anything else I can supply to assist troubleshooting, please let me know.
Here's my map.jsx
import React from 'react';
import 'leaflet';
export default class Map extends React.Component {
componentDidMount() {
this.map = new L.Map('map', {
center: new L.LatLng(53.15, 0.54),
zoom: 8,
layers: L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
})
});
this.layersControl = L.control.layers().addTo(this.map);
}
render() {
return (
<div id="map-container" className="pure-u-1">
<div id="map"></div>
</div>
);
}
}
and my app.jsx
import React from 'react';
import Nav from './nav/nav.jsx';
import NavButton from './nav/navbutton.jsx';
import Map from './map.jsx';
export default class App extends React.Component {
render() {
return (
<div className="pure-g">
<Nav>
<NavButton>Test</NavButton>
</Nav>
<Map />
</div>
);
}
}
as well as the webpack.config.js
module.exports = {
entry: "./src/index.jsx",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
},
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.png$/, loader: "url-loader", query: { mimetype: "image/png" } },
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "url-loader?limit=10000&mimetype=application/font-woff&name=fonts/[name].[ext]"
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader?name=fonts/[name].[ext]"
}
]
}
};