Using TailwindCSS with Symfony Webpack Encore - javascript

I'm having trouble setting up TailwindCSS with Symfony and I'm not sure what's wrong
webpack.config.js
var Encore = require('#symfony/webpack-encore');
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
Encore
.setOutputPath('public/build/')
.setPublicPath('/build')
.addStyleEntry('tailwind', './assets/css/tailwind.css')
.enablePostCssLoader((options) => {
options.config = {
// directory where the postcss.config.js file is stored
path: './postcss.config.js'
};
})
.splitEntryChunks()
.enableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
})
;
module.exports = Encore.getWebpackConfig();
tailwind.css
#tailwind base;
#tailwind components;
#tailwind utilities;
postcss.config.js
let tailwindcss = require('tailwindcss');
module.exports = {
plugins: [
tailwindcss('./tailwind.config.js'), // your tailwind.js configuration file path
require('autoprefixer'),
require('postcss-import')
]
}
tailwind.config.js
module.exports = {
theme: {
extend: {}
},
variants: {},
plugins: [],
prefix:,
}
Here is the output of yarn encore dev
yarn run v1.22.0 Running webpack ...
ERROR Failed to compile with 1 errors
error in ./assets/css/tailwind.css
ValidationError: Invalid options object. PostCSS Loader has been
initialized using an options object that does not match the API
schema.
options has an unknown property 'config'. These properties are valid: object { postcssOptions?, execute?, sourceMap? }
Entrypoint tailwind = runtime.js
ModuleBuildError: Module build failed (from
./node_modules/postcss-loader/dist/cjs.js): ValidationError: Invalid
options object. PostCSS Loader has been initialized using an options
object that does not match the API schema.
options has an unknown property 'config'. These properties are valid: object { postcssOptions?, execute?, sourceMap? }
at validate (./node_modules/schema-utils/dist/validate.js:104:11)
at Object.loader (./node_modules/postcss-loader/dist/index.js:43:29)" -t "Webpack
Encore" error Command failed with exit code 2. info Visit
https://yarnpkg.com/en/docs/cli/run for documentation about this
command
I have node v14.15.0, I tried to yarn upgrade. Here are my direct dependencies :
success Saved lockfile.
success Saved 598 new dependencies.
info Direct dependencies
├─ #symfony/webpack-encore#0.33.0
├─ autoprefixer#10.1.0
├─ core-js#3.8.1
├─ datatables.net#1.10.22
├─ postcss-import#13.0.0
├─ postcss-loader#4.1.0
├─ postcss#8.2.1
├─ regenerator-runtime#0.13.7
├─ tailwindcss#2.0.2
└─ webpack-notifier#1.12.0
Like I said previously, I'm not sure what is wrong and my attempt to correct the problem on my own failed. The error seems to be coming from postcss or at least something inside my file that postcss doesn't like.
Could someone explain me where is this error coming from and how to correct it ?

Looks like postcss-loader has changed their api already by moving config option into postcssOptions instead.
Let's try with new option as following:
Encore
// ...
.enablePostCssLoader((options) => {
// new option outlined here https://webpack.js.org/loaders/postcss-loader/
options.postcssOptions = {
config: './postcss.config.js',
},
})

Related

How to convert postcss.config.js and tailwind.config.js to ES modules?

I created a new Vue app using Vite via npm init vue#latest. I added TailwindCSS to the project based on the official guide.
Running npm run lint throws errors
error 'module' is not defined no-undef
because it wants postcss.config.js and tailwind.config.js to be ES modules (I think).
When converting postcss.config.js from
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
to
export const plugins = {
tailwindcss: {},
autoprefixer: {},
};
and tailwind.config.js from
module.exports = {
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
to
export const content = ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"];
export const theme = {
extend: {},
};
export const plugins = [];
and running npm run dev the app crashes with the error
[vite] Internal server error: Unexpected token 'export'
Plugin: vite:css
How do I solve this linting error?
You can actually keep those config files as CommonJS. ESLint's env needs to be set to node in those config files because Node is the actual environment during the build.
Option 1: Use inline comment to configure ESLint
Insert this comment at the top of postcss.config.js and tailwind.config.js:
/* eslint-env node */
Option 2: Configure env for *.config.js
Configure overrides to set env for *.config.js files:
// .eslintrc.cjs
module.exports = {
⋮
overrides: [
{
files: ['*.config.js'],
env: {
node: true,
},
},
],
}
If using VS Code, you'll likely need to restart the ESLint server (or the IDE) to reload the configuration.
Option 3: Disable ESLint rules for *.config.js
Configure ignorePatterns to not lint these config files:
// .eslintrc.cjs
module.exports = {
⋮
ignorePatterns: ['*.config.js'],
}
If using VS Code, you'll likely need to restart the ESLint server (or the IDE) to reload the configuration.
Rename the files to postcss.config.cjs resp. tailwind.config.cjs. Note the c in cjs, which stands fro CommonJS Module.

"Serverless-offline: route not found." running an AWS Lambda function in offline mode

This question is pretty much the same as Serverless offline not getting route, but since that one was not answered I'm asking again. I'm trying to follow this article, https://medium.com/#awesome1888/how-to-use-serverless-locally-with-webpack-and-docker-5e268f71715, on how to deploy a Lambda function with Serverless.
I have a directory with the following structure:
> tree -I node_modules
.
├── package-lock.json
├── package.json
├── serverless.yml
├── src
│   ├── handler.js
│   └── index.js
└── webpack.config.js
where serverless.yml reads
service: my-first-lambda
plugins:
- serverless-webpack
- serverless-offline
provider:
name: aws
runtime: nodejs10.x
region: us-east-1
stage: dev
functions:
hello:
handler: src/handler.main
events:
- http:
path: /hello
method: any
custom:
webpack:
includeModules: true
src/index.js reads
import moment from 'moment';
const handler = async (event, context) => {
const body = await new Promise((resolve) => {
setTimeout(() => {
resolve(`Hello, this is your lambda speaking. Today is ${moment().format('dddd')}`)
}, 2000);
});
return {
statusCode: 200,
body,
};
}
export default handler;
src/handler.js reads
export { default as main } from './index';
and webpack.config.js reads
const path = require("path");
const nodeExternals = require("webpack-node-externals");
const slsw = require("serverless-webpack");
module.exports = {
entry: slsw.lib.entries,
target: "node",
mode: slsw.lib.webpack.isLocal ? "development" : "production",
externals: [nodeExternals()],
output: {
libraryTarget: "commonjs",
path: path.join(__dirname, ".webpack"),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
plugins: ["#babel/plugin-proposal-object-rest-spread"]
}
}
]
}
]
}
};
The problem is when I start up the function in offline mode, it seems to have only one very specific route:
>
npx serverless offline start --region us-east-1 --noTimeout --port 3000 --host 0.0.0.0
Serverless: Bundling with Webpack...
Time: 1203ms
Built at: 08/30/2019 2:35:10 PM
Asset Size Chunks Chunk Names
src/handler.js 6.81 KiB src/handler [emitted] src/handler
Entrypoint src/handler = src/handler.js
[./src/handler.js] 42 bytes {src/handler} [built]
[./src/index.js] 1.64 KiB {src/handler} [built]
[moment] external "moment" 42 bytes {src/handler} [built]
Serverless: Watching for changes...
Serverless: Starting Offline: dev/us-east-1.
Serverless: Routes for hello:
Serverless: POST /{apiVersion}/functions/my-first-lambda-dev-hello/invocations
Serverless: Offline [HTTP] listening on http://0.0.0.0:3000
Serverless: Enter "rp" to replay the last request
and if I go to http://localhost:3000/hello, I get this response:
{"statusCode":404,"error":"Serverless-offline: route not found.","currentRoute":"get - /hello","existingRoutes":["post - /{apiVersion}/functions/my-first-lambda-dev-hello/invocations"]}
Any idea why this is not working? (I've perused https://serverless.com/framework/docs/ but couldn't quickly find an answer).
I had this issue and if anyone comes across it, this github comment fixed my issue.
You can run $ sls offline start --noPrependStageInUrl or add the following to your serverless.yml file
custom:
serverless-offline:
noPrependStageInUrl: true
According to the comment:
I had this problem with anything 6+, this was due to the fact that it now defaults to appending the staging name to the url path. To revert to the old way, you need to add --noPrependStageInUrl to the cli or in the serverless file custom: serverless-offline noPrependStageInUrl: true to revert to previous setting. I'm testing it his out but #dherault the functionality is not reflecting what is actually happening in AWS.
I was using serverless-offline: "6.7.0" and my index.handler was as below:
const serverless = require("serverless-http");
const express = require("express");
const app = express();
app.get("/", function (req, res) {
res.send("Hello World!");
});
module.exports.handler = serverless(app);
And my serverless.yml
plugins:
- serverless-offline
custom:
serverless-offline:
noPrependStageInUrl: true
provider:
name: aws
runtime: nodejs12.x
stage: dev
region: eu-west-2
functions:
app:
handler: src/index.handler
events:
- http: ANY /
- http: "ANY {proxy+}"
Apologies this isn't exactly a great answer but hopefully, someone comes across this and it is a solution to their problem.
Looks like you've got a whitespace issue in your serverless.yml file.
Try indenting path and method under the http block:
functions:
hello:
handler: src/handler.main
events:
- http:
path: /hello
method: any
for setup a quick example using serverless template :
sls create -h
output :
create ........................ Create new Serverless service
--template / -t .................... Template for the service. Available templates: "aws-clojure-gradle", "aws-clojurescript-gradle", "aws-nodejs", "aws-nodejs-typescript", "aws-alexa-typescript", "aws-nodejs-ecma-script", "aws-python", "aws-python3", "aws-groovy-gradle", "aws-java-maven", "aws-java-gradle", "aws-kotlin-jvm-maven", "aws-kotlin-jvm-gradle", "aws-kotlin-nodejs-gradle", "aws-scala-sbt", "aws-csharp", "aws-fsharp", "aws-go", "aws-go-dep", "aws-go-mod", "aws-ruby", "aws-provided", "azure-nodejs", "cloudflare-workers", "cloudflare-workers-enterprise", "cloudflare-workers-rust", "fn-nodejs", "fn-go", "google-nodejs", "google-python", "google-go", "kubeless-python", "kubeless-nodejs", "openwhisk-java-maven", "openwhisk-nodejs", "openwhisk-php", "openwhisk-python", "openwhisk-ruby", "openwhisk-swift", "spotinst-nodejs", "spotinst-python", "spotinst-ruby", "spotinst-java8", "plugin" and "hello-world"
step1: so for generated a new nodejs example with an api :
sls create -t aws-nodejs-ecma-script -n service-name-hello-world
step2: install serverless-offline :
npm install serverless-offline -D
step3: in serverless.yml
plugins:
- serverless-webpack
- serverless-offline
step4 : start local server
serverless offline start -r us-west-1 --stage dev
github Example
git clone https://github.com/ysfmag/aws-serverless-nodejs-example
cd aws-serverless-nodejs-example
yarn
yarn start
serverless.yml
to define an api in your serverless framework you need to respect yaml format , and in the path variable you dont need to start with '/hello' just 'hello' will work .
functions:
hello:
handler: src/handler.main
events:
- http:
path: hello
method: get

Cannot import stylesheets from node_modules without tilde (~)

I'm trying to create a simple web app with material-components-vue and vue-cli with webpack, however, I found out that I cannot import stylesheets from node_modules without a preceding ~.
I have tried several webpack/vue-cli configs, and ended up with a config in vue.config.js passing loader options.
My vue.config.js looks like this:
module.exports = {
css: {
loaderOptions: {
sass: {
includePaths: [
'./node_modules', //here I include node_modules
]
},
}
}
}
So I expect to be able to import stuff like so:
#import 'normalize/normalize'
(assuming I have a directory called normalize in my node_modules which contains a file normalize.scss)
However, webpack throws an error, saying it cannot find the module.
But, this does work:
#import '~normalize/normalize'
This wouldn't be a problem if all #imports were written by me, but because I use a third-party module which has #imports inside them, webpack fails to compile.
EDIT 1:
As #Styx asked to
Share more configs, please
and
show the output of vue inspect --rule scss, and the whole file with this problematic import
Here it is:
My problematic file is pretty empty:
<template>
<div id="app">
<m-button>Hello</m-button>
</div>
</template>
<script>
import Vue from 'vue'
import Button from 'material-components-vue/dist/button'
Vue.use(Button)
export default {
name: 'App',
components: {
}
</script>
<style lang="scss">
#import "~material-components-vue/dist/button/styles"; //this works
#import "material-components-vue/dist/button/styles"; //but this does not
</style>
My output from vue inspect --rule scss is located here
All other configs are as generated by vue init webpack <name>
EDIT 2: Exact steps to reproduce this issue:
Initialize a vue-webpack app:
vue init webpack .
Vue build: Runtime + Compiler (Default)
Vue-router: no
Package manager: npm
Then, install sass-loader
npm i -D sass-loader node-sass
Create a file vue.config.js and populate it with the following:
module.exports = {
css: {
loaderOptions: {
sass: {
includePaths: [
'./node_modules', //here I include node_modules
]
},
}
}
}
After that, install a module containing scss/sass
(E.g. for material-components-web, npm i material-components-web)
Then, create an import to a stylesheet located in node_modules, like so:
#import '#material/button/mdc-button'; //mdc-button comes with material-components-web
Finally, start the dev server:
npm run dev
It will throw the following error:
ERROR Failed to compile with 1 errors 11:36:35 AM
error in ./src/App.vue
Module build failed:
#import '#material/button/mdc-button';
^
File to import not found or unreadable: #material/button/mdc-button.
in /home/maxim/projects/holiday.js/stackoverflow/src/App.vue (line 18, column 1)
# ./node_modules/vue-style-loader!./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compil
er?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasInlineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"s
ourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue 4:14-359 13:3-17:5 14:22-367
# ./src/App.vue
# ./src/main.js
# multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/main.js
By the way, in the first example I wanted to import material-components-vue/dist/foo/styles, but here I import #material/foo.
In this configuration your vue.config.js is ignored. This file is used by #vue/cli-service, but you're using webpack-dev-server instead. Thus, your sass-loader doesn't receive this includePaths option.
You can either use modern vue create <app-name> command, or if you want to modify existing project:
Open build/utils.js file.
Find return ... in exports.cssLoaders function:
return {
...
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
...
}
Modify it like this:
const includePaths = [path.resolve(__dirname, '..', 'node_modules')];
return {
...
sass: generateLoaders('sass', { indentedSyntax: true, includePaths }),
scss: generateLoaders('sass', { includePaths }),
...
}
Remove unused vue.config.js file.

Cannot find module with Webpack, Typescript, custom module directory

What I'm trying to do
I am wrote a dummy module my-component which essentially exports a single class Something. I placed it in app/modules/. Now I am tying to access it using the import Syntax from app/app.js:
import { Something } from 'my-component';
Expectation: With my current Webpack configuration (below) I would expect this to work.
Actual: This throws the error:
ERROR in [default] /<project_dir>/app/app.ts:1:26
Cannot find module 'my-component/Something'.
What I tried to fix it
I know the module in itself is defined correctly, because
I can import it using a relative path: import { Something } from './my-component'
I can import it as-is, if I move the module to node_modules/my-component.
The only combination that fails is importing it without a relative path from my modules/ directory. So I think the issue might be my Webpack configuration.
Setup Details
As you can see below, I have two directories listed as resolve.root:
project_dir/app
project_dir/node_modules
It seems to manage to resolve from node_modules, just not from app.
Project layout
Webpack
project_dir/
├── app/ context, resolve.root
│ ├── app.ts
│ └── my-component/
│ ├── index.ts
│ └── Something.ts
├── webpack.config.js
├── node_modules/ resolve.root
│ ├── ...
│ ├── ...
│ └── ...
└── dist/
└── ...
app/app.ts
import { Something } from 'my-component/Something';
app/my-component/index.ts
export { Something } from './Something'
app/my-component/Something.ts
class Something {
}
export { Something };
webpack.config.js
var path = require('path'),
ROOT = path.resolve(__dirname, '.');
module.exports = {
context: path.resolve(ROOT, 'app'),
entry: 'app.ts',
output: {
path: path.resolve(ROOT, 'dist'),
filename: '[name]-[hash].js'
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'awesome-typescript' }
]
},
resolve: {
root: [
path.resolve(__dirname, 'app'),
path.resolve(__dirname, 'node_modules')
],
extensions: [
'', '.ts', '.js'
]
}
};
EDIT
Fixed the project layout.
Cannot find module
If you experience this issue with dynamic module loading using ESNEXT,
you have to add "moduleResolution": "node" to your tsconfig.json.
I found an easier solution than the previously accepted one:
In your typescript configuration, set the baseUrl in the compilerOptions:
tsconfig.json:
{
"compilerOptions": {
"baseUrl": "./app",
...
},
...
}
Explanation:
Webpack and Typescript use node module resolution by default, which is fine.
When setting up custom module folders though, you need to configure them in both the Webpack and the Typescript config.
Changes to the Webpack module resolution config are not propagated to the Typescript compiler.
Ok. I created a replica of your project structure. It seems that the case is that the import statement does not behave the same as the require, AND, webpack resolve.root config works as expected with it.
For the modules, change your import statements to require like this:
app.ts
// Define require function for TypeScript to know that it
// will exist at runtime
declare function require(name:string);
// Require your module
var Something = require('my-component/Something');
// var myComponent = require('my-component');
my-component/Something.ts
// Export something (used a function to test)
export function Something() {
console.log("Hello");
}
my-component/index.ts
// Definition of require function as mentioned before
declare function require(name:string);
// Passing other modules
var exportedModules = {
Something: require("my-component/Something")
};
export default exportedModules;
Like this, it will work without problems and resolve with the module names as you defined in Webpack. Unfortunately, I couldn't achieve it with the import.
I pushed the solution to a repository. Check it out if you need!

Webpack bundle named requirejs modules

In my company we have a significant AMD RequireJS code base and I am trying to use webpack to bundle some of it.
Here is what the architecture looks like:
somedir
│ app.js
│
└───anotherdir
|
├─── module1
│ file1.js
│ file2.js
│
├─── module2
│ file3.js
│
└─── module3
file4.js
file5.js
file6.js
Each file is written like that :
define('ATAG/MODULE/ID, ['somedeps'], function (somedeps) {});
So for instance file1.js could look like
define('ATAG/module1/file1, [], function () {});
And we have a RequireJS config which maps ATAG to anotherdir and we possibly have some more config for different tags.
Now I am trying to create a bundle from app.js with webpack but I have no idea of how to replicate the behavior we have with require.config({ paths: { ATAG: 'anotherdir' } }).
So far my attempts with resolve.alias have not been successful.
Is it even possible to achieve something like this with webpack based on our usage of RequireJS (not requiring relative paths) ?
Thank you.
You were on the right path with resolve.alias:
// foo.js
var a = require('ATAG'); // resolved to anotherdir/index.js
var b = require('ATAG/bar'); // resolved to anotherdir/bar.js
// webpack.config.js
const path = require('path');
module.exports = {
entry: './foo',
output: {
filename: 'bundle.js'
},
resolve: {
alias: {
ATAG: path.join(__dirname, '/anotherdir')
}
}
};

Categories