-
-
Notifications
You must be signed in to change notification settings - Fork 201
Question : Proper way to handle angular 2 or 4 #93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'd be very happy to add Angular support :). I haven't looked into it at all yet and I don't use Angular. For Vue, it was of adding the In other words, PR very welcome - even if it's just a work-in-progress PR. |
Use the angular CLI and then run I've asked if the guys from the Angular Gitter.im chat if they could take a peek at this, so fingers crossed! :) |
Here's a default output. const fs = require('fs');
const path = require('path');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');
const postcssUrl = require('postcss-url');
const cssnano = require('cssnano');
const { NoEmitOnErrorsPlugin, SourceMapDevToolPlugin, NamedModulesPlugin } = require('webpack');
const { GlobCopyWebpackPlugin, BaseHrefWebpackPlugin } = require('@angular/cli/plugins/webpack');
const { CommonsChunkPlugin } = require('webpack').optimize;
const { AotPlugin } = require('@ngtools/webpack');
const nodeModules = path.join(process.cwd(), 'node_modules');
const realNodeModules = fs.realpathSync(nodeModules);
const genDirNodeModules = path.join(process.cwd(), 'src', '$$_gendir', 'node_modules');
const entryPoints = ["inline","polyfills","sw-register","styles","vendor","main"];
const minimizeCss = false;
const baseHref = "";
const deployUrl = "";
const postcssPlugins = function () {
// safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193
const importantCommentRe = /@preserve|@license|[@#]\s*source(?:Mapping)?URL|^!/i;
const minimizeOptions = {
autoprefixer: false,
safe: true,
mergeLonghand: false,
discardComments: { remove: (comment) => !importantCommentRe.test(comment) }
};
return [
postcssUrl({
url: (URL) => {
// Only convert root relative URLs, which CSS-Loader won't process into require().
if (!URL.startsWith('/') || URL.startsWith('//')) {
return URL;
}
if (deployUrl.match(/:\/\//)) {
// If deployUrl contains a scheme, ignore baseHref use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${URL}`;
}
else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
}
else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${URL}`.replace(/\/\/+/g, '/');
}
}
}),
autoprefixer(),
].concat(minimizeCss ? [cssnano(minimizeOptions)] : []);
};
module.exports = {
"resolve": {
"extensions": [
".ts",
".js"
],
"modules": [
"./node_modules",
"./node_modules"
],
"symlinks": true
},
"resolveLoader": {
"modules": [
"./node_modules",
"./node_modules"
]
},
"entry": {
"main": [
"./src/main.ts"
],
"polyfills": [
"./src/polyfills.ts"
],
"styles": [
"./src/styles.css"
]
},
"output": {
"path": path.join(process.cwd(), "dist"),
"filename": "[name].bundle.js",
"chunkFilename": "[id].chunk.js"
},
"module": {
"rules": [
{
"enforce": "pre",
"test": /\.js$/,
"loader": "source-map-loader",
"exclude": [
/\/node_modules\//
]
},
{
"test": /\.json$/,
"loader": "json-loader"
},
{
"test": /\.html$/,
"loader": "raw-loader"
},
{
"test": /\.(eot|svg)$/,
"loader": "file-loader?name=[name].[hash:20].[ext]"
},
{
"test": /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|cur|ani)$/,
"loader": "url-loader?name=[name].[hash:20].[ext]&limit=10000"
},
{
"exclude": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.css$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.scss$|\.sass$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "sass-loader",
"options": {
"sourceMap": false,
"precision": 8,
"includePaths": []
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.less$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "less-loader",
"options": {
"sourceMap": false
}
}
]
},
{
"exclude": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.styl$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "stylus-loader",
"options": {
"sourceMap": false,
"paths": []
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.css$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.scss$|\.sass$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "sass-loader",
"options": {
"sourceMap": false,
"precision": 8,
"includePaths": []
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.less$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "less-loader",
"options": {
"sourceMap": false
}
}
]
},
{
"include": [
path.join(process.cwd(), "src/styles.css")
],
"test": /\.styl$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"importLoaders": 1
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins
}
},
{
"loader": "stylus-loader",
"options": {
"sourceMap": false,
"paths": []
}
}
]
},
{
"test": /\.ts$/,
"loader": "@ngtools/webpack"
}
]
},
"plugins": [
new NoEmitOnErrorsPlugin(),
new GlobCopyWebpackPlugin({
"patterns": [
"assets",
"favicon.ico"
],
"globOptions": {
"cwd": path.join(process.cwd(), "src"),
"dot": true,
"ignore": "**/.gitkeep"
}
}),
new ProgressPlugin(),
new SourceMapDevToolPlugin({
"filename": "[file].map[query]",
"moduleFilenameTemplate": "[resource-path]",
"fallbackModuleFilenameTemplate": "[resource-path]?[hash]",
"sourceRoot": "webpack:///"
}),
new HtmlWebpackPlugin({
"template": "./src/index.html",
"filename": "./index.html",
"hash": false,
"inject": true,
"compile": true,
"favicon": false,
"minify": false,
"cache": true,
"showErrors": true,
"chunks": "all",
"excludeChunks": [],
"title": "Webpack App",
"xhtml": true,
"chunksSortMode": function sort(left, right) {
let leftIndex = entryPoints.indexOf(left.names[0]);
let rightindex = entryPoints.indexOf(right.names[0]);
if (leftIndex > rightindex) {
return 1;
}
else if (leftIndex < rightindex) {
return -1;
}
else {
return 0;
}
}
}),
new BaseHrefWebpackPlugin({}),
new CommonsChunkPlugin({
"minChunks": 2,
"async": "common"
}),
new CommonsChunkPlugin({
"name": [
"inline"
],
"minChunks": null
}),
new CommonsChunkPlugin({
"name": [
"vendor"
],
"minChunks": (module) => {
return module.resource
&& (module.resource.startsWith(nodeModules)
|| module.resource.startsWith(genDirNodeModules)
|| module.resource.startsWith(realNodeModules));
},
"chunks": [
"main"
]
}),
new NamedModulesPlugin({}),
new AotPlugin({
"mainPath": "main.ts",
"hostReplacementPaths": {
"environments/environment.ts": "environments/environment.ts"
},
"exclude": [],
"tsConfigPath": "src/tsconfig.app.json",
"skipCodeGeneration": true
})
],
"node": {
"fs": "empty",
"global": true,
"crypto": "empty",
"tls": "empty",
"net": "empty",
"process": true,
"module": false,
"clearImmediate": false,
"setImmediate": false
},
"devServer": {
"historyApiFallback": true
}
}; |
@weaverryan is this useful? I've also been publishing a link to this issue on various platforms to see if people can help out. |
@stof do you perhaps have a clue for us? 😄 |
This does help. I actually don't see anything special in this setup, except for enabling typescript and also the @isdp It might already be possible to use Encore with Angular just by calling Thanks! |
Hi and thanks for your answers. Actually I ended up using React. As I just landed on the symfony project, I've been given the goal to implement a reactive solution. But Angular appeared to be a bad choice because of its monolithique aspect. |
Hi, @weaverryan It's working out of the box as you already guessed. But Angular 2+ is not that big benefit for a Symfony application, because it's more useful for single page applications then for mixing with twig. I will give vue.js a try instead. I hope getting Angular 5 running using Webpack Encore will help somebody, anyway. Angular 5 (Angular 2-4 will need another plugin (AotPlugin) to be injected) can be added like this...
|
Holy reproducing feces! This would help a ton as I won't have to switch projects to work on the angular frontend and a Symfony based API as backend at the same time 👌 |
I have managed to put Angular5 app into Symfony 3 project with 2 step compiling. Here is what I have done (it was some time ago so I may have missed sth):
you can also use ng serve to develop but you will not have your twig template |
@mateusz-sawit that worked really well. Also, something you may have forgotten (at least required for me), was to also add the generated |
@Rebolon You can probably achieve the same thing by running |
@Lyrkan maybe we would have to eject the webpack config from angular-cli ? (i delete my post by mistake... instead of editing it: so what i was saying was (summarised): with previous post we don't have a watch system) |
@Rebolon you can use ng serve in my configuration - in package.json add script: "serve": "ng serve" and then run npm serve - you will have your angular app running alone but without "symfony" content moreover you should be able to use any ng commands in your project - i.e. ng generate, and the generated content should be put in right place. |
For instance i decided to use only This is for a ProofOfConcept so i think it's enough. The bad thing is that even if it rebuild files when there is a changes, it doesn't refressh the browser. I have to setup something manually but i'm not sure it's the best idea. I think in fact that if i need angular it must be a standalone application whereas if i need to embed JS in PHP app, then it's more reliable to use React or VueJS |
@mateusz-sawit Your idea seems good but your files are being webpacked by angular CLI, not by encore, right? I see a problem here: if you want to uglify the files you can't use encore for it, you should use angular CLI so in Encore config you don't now the name for each addEntry(). How did you solve it? Are you uglifying the JS files? if so are you doing it from Encore? (I think ng build prod makes more things than just uglifying) |
Hi, I have added bash script to remove hash part of ng generated files. I run this between ng build and encore |
@mateusz-sawit Thanks for your quick response, we are going to use a bash script to generate the manifest.json avoiding Encore. |
BTW @mateusz-sawit you can use |
Hey @mateusz-sawit thankx for your gr8 post abt putting angular into a symfony app. |
Hey @vichanse for now I don't have code that I can share but in my working app I have modified a little bit way I am doing it. Because putting angular build results into webpack required compiling angular files twice I use separate builds for angular and symfonny assets.
You don't need to add anything to symfony's webpack.config.js
|
@mateusz-sawit Hello. I added angular to my symfony application but I have some problems.
Maybe You had the same problem? |
@andrewchaika Hi, I am not using encore to compile Symfony app, see my comment on 16 Sep. I am compiling ng app separately, copying/linking generated sources to /web/build dir and manually or with script updating manifest.json file. It solved many problems with compiling angular with encore. |
Coming back to this , any updates on how i should procede |
Thank you for this issue. |
1 similar comment
Thank you for this issue. |
Hi there,
I'm willing to work with symfony and webpack encore, and add angular 4 to it. Is there any proper way to handle this ?
Thanks
The text was updated successfully, but these errors were encountered: