I am trying to use the #ngtools/webpack plugin to create an AoT version of my Angular 4 app within webpack 2, but I am having difficulty understanding what this plugin produces.
In particular, I have a main.aot.ts entry point in my webpack for AoT, which looks like this:
// main.aot.ts
import { platformBrowser } from '#angular/platform-browser';
import { AppModuleNgFactory } from '../compiled/src/app/app.module.ngfactory';
const platform = platformBrowser();
platform.bootstrapModuleFactory(AppModuleNgFactory);
and an extract of my webpack.config.js looks like this:
if (envOptions.MODE === 'prod') {
config.module.rules.push(
{test: /\.ts$/, loader: '#ngtools/webpack'}
);
config.plugins.push(
new AotPlugin({
tsConfigPath: path.resolve(__dirname, './app/tsconfig.json'),
entryModule: path.resolve(__dirname, './app/src/app.module#AppModule')
}),
new webpack.optimize.UglifyJsPlugin({
beautify: false,
mangle: {
screw_ie8: true,
keep_fnames: true
},
compress: {
warnings: false,
screw_ie8: true
},
comments: false
})
);
}
Does this #ngtools/webpack plugin generate module files in the same way that the ngc compiler does, for inclusion in main.aot.ts? If not, how does it work? There aren't many examples of this on the web.
The thing about #ngtools/webpack is that it creates those .ngfactory files in memory. Therefore there is no need to have any main.aot.ts.
main.ts:
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { enableProdMode } from '#angular/core';
import { AppModule } from './app.module';
if (process.env.ENV === 'production') {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
In your webpack config:
var aotPlugin = new ngToolsWebpack.AotPlugin({
tsConfigPath: helpers.root('tsconfig.json'),
entryModule: helpers.root('app', 'app.module#AppModule')
});
module: {
rules: [
{
test: /\.ts$/,
use: '#ngtools/webpack'
}
]
},
plugins: [
aotPlugin
]
Now, when you run the webpack the #ngtools/webpack will internally compile the Angular out of the box.
It's worth noting it's a good practice to have #ngtools/webpack only for production build because error messages it produces are bollocks.
Related
I'm trying to solve the Vite build error I get:
RollupError: Invalid value "iife" for option "output.format" - UMD and IIFE output formats are not supported for code-splitting builds.
The file name reported with this error points to
my web worker code, so I assumed that this setting belongs to the worker section in vite.config.ts:
import { defineConfig } from "vite";
import preact from "#preact/preset-vite";
import basicSsl from "#vitejs/plugin-basic-ssl";
import { NodeGlobalsPolyfillPlugin } from "#esbuild-plugins/node-globals-polyfill";
import { NodeModulesPolyfillPlugin } from "#esbuild-plugins/node-modules-polyfill";
import rollupNodePolyFill from "rollup-plugin-node-polyfills";
export default defineConfig({
plugins: [
preact(),
basicSsl(),
],
server: {
port: 3001,
https: true,
},
optimizeDeps: {
esbuildOptions: {
// Node.js global to browser globalThis
define: {
global: "globalThis",
},
// Enable esbuild polyfill plugins
plugins: [
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true,
}),
NodeModulesPolyfillPlugin(),
],
},
},
worker: {
rollupOptions: {
output: {
format: "esm",
},
},
},
build: {
rollupOptions: {
plugins: [
// Enable rollup polyfills plugin
// used during production bundling
rollupNodePolyFill(),
],
output: {
format: "esm",
},
},
},
});
Additionally, I set the output format in the build rollup options. However, neither of the two settings are applied and I still get the said error.
What is the correct way to change the rollup output format setting in Vite?
The worker output format must be specified directly in the worker config key, not its rollup options:
import { defineConfig } from "vite";
import preact from "#preact/preset-vite";
import basicSsl from "#vitejs/plugin-basic-ssl";
import { NodeGlobalsPolyfillPlugin } from "#esbuild-plugins/node-globals-polyfill";
import { NodeModulesPolyfillPlugin } from "#esbuild-plugins/node-modules-polyfill";
import rollupNodePolyFill from "rollup-plugin-node-polyfills";
export default defineConfig({
plugins: [
preact(),
basicSsl(),
],
server: {
port: 3001,
https: true,
},
optimizeDeps: {
esbuildOptions: {
// Node.js global to browser globalThis
define: {
global: "globalThis",
},
// Enable esbuild polyfill plugins
plugins: [
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true,
}),
NodeModulesPolyfillPlugin(),
],
},
},
worker: {
format: "es",
},
build: {
rollupOptions: {
plugins: [
// Enable rollup polyfills plugin
// used during production bundling
rollupNodePolyFill(),
],
output: {
format: "esm",
},
},
},
});
I have an app folder with some images that are used by the external script and I need to include those images in the dist build folder.
I tried to log files that go to output and those images are not included. I tried to add assetsInclude property but seems that property is not for that purpose.
How can I include some specific images in dist folder that aren't imported explicitly ?
Here is my vite.config.js file.
import { resolve, parse } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
base: '/',
root: resolve(__dirname, 'app'),
assetsInclude: ['/app/images/externalImage.png'],
build: {
emptyOutDir: true,
rollupOptions: {
output: {
dir: './dist',
assetFileNames: (asset) => {
console.log(parse(asset.name).name);
if (parse(asset.name).name === 'externalImage') {
return "images/src/[name][extname]";
}
return "assets/[name].[hash][extname]";
}
},
},
},
});
In my js file which is included as a module inside the HTML file, I added string that you can see below. Here is details of how to expose the current module URL.
app/js/app.js
new URL("../images/src/externalImage.png", import.meta.url);
Also changed a bit config - added outDir prop:
import { resolve, parse } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
base: '/',
root: resolve(__dirname, 'app'),
build: {
outDir: '../dist',
emptyOutDir: true,
rollupOptions: {
output: {
assetFileNames: (asset) => {
if (parse(asset.name).name === 'externalImage') {
return "images/src/[name][extname]";
}
return "assets/[name].[hash][extname]";
}
},
},
},
});
I am trying to scaffold an Angular 6 app by hand (ie not using the CLI). I was doing OK until I ran into the following error when running webpack:
ERROR in window is not defined
Now from googling around it looks like I'm missing some polyfills since webpack uses node in order to generate it's output. I've reviewed the examples on Angular's site and added the polyfills.ts file to my application but I still can't get rid of the error.
Here is my webpack.confg.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ScriptExtPlugin = require('script-ext-html-webpack-plugin');
const { AngularCompilerPlugin } = require('#ngtools/webpack');
module.exports = function() {
return {
entry: {
index: "./src/client/client.ts",
polyfills: "./src/client/polyfills.ts"
},
output: {
path: __dirname + "/client-dist",
filename: "[name].client.js"
},
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
loader: '#ngtools/webpack'
},
{
test: /\.html$/,
loader: 'html-loader',
},
{
test: /\.css$/,
loader: ["style-loader", "css-loader"]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: __dirname + '/src/client/index.html',
output: __dirname + '/client-dist',
inject: 'head'
}),
new ScriptExtPlugin({
defaultAttribute: 'defer'
}),
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: './src/client/app/app.module#AppModule'
})
]
}
}
My polyfills.ts file:
import 'core-js/es6';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
And my client.ts file (entry point of my application):
import './polyfills'
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
I'm sure I'm just doing something stupid but any help would be appreciated. Thanks!
EDIT 1:
After reading the article posted by #SureshKumarAriya I tried changing the following in my webpack.config:
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: './src/client/app/app.module#AppModule',
skipCodeGeneration: true // This is new
})
And I get a different error: ERROR in Resolution of relative paths requires a containing file.
I'm guessing this means it can't resolve one of the typescript files I reference in client.ts? I'm not sure this has gotten me any closer but still interesting.
As always thanks for the help!
Inside output cofiguration. please add globalObject: "this".
output: {
// ...
globalObject: "this"
}
https://github.com/markdalgleish/static-site-generator-webpack-plugin/issues/130
Seems like your dependencies still rely on the window object.
Do validate
typeof window !== 'undefined'
Please refer to the following link.
Im trying to publish a project to npm that contains two or more Vue components so i can import, register and use both components like this:
import Component1 from 'npm-package'
import Component2 from 'npm-package'
this is my webpack file:
const webpack = require('webpack');
const merge = require('webpack-merge');
const path = require('path');
var config = {
output: {
path: path.resolve(__dirname + '/dist/'),
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
include: __dirname,
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.css$/,
loader: 'style!less!css'
}
]
},
externals: {
moment: 'moment'
},
plugins: [
new webpack.optimize.UglifyJsPlugin( {
minimize : true,
sourceMap : false,
mangle: true,
compress: {
warnings: false
}
} )
]
};
module.exports = [
merge(config, {
entry: path.resolve(__dirname + '/src/plugin.js'),
output: {
filename: 'vue-project.min.js',
libraryTarget: 'window',
library: 'VueProject',
}
}),
merge(config, {
entry: path.resolve(__dirname + '/src/index.js'),
output: {
filename: 'vue-project.js',
libraryTarget: 'umd',
library: 'vue-project',
umdNamedDefine: true
},
resolve: {
extensions: ['', '.js', '.vue'],
alias: {
'src': path.resolve(__dirname, '../src'),
'components': path.resolve(__dirname, '../src/components')
}
}
})
];
and this is the index.js file i'm using as the entry point for the build process
import Component1 from './components/folder1/Component1.vue'
import Component1 from './components/folder2/Component2.vue'
export default {
components: {
Component1,
Component2
}
}
The build process using npm run build works fine and i can publish the project to npm and install it using npm install. Importing and using it works fine to, but when i run my project i get the error:
failed to mount component: template or render function not defined.
All other posts o found regarding this error did not solve my problem, as none of them tried to export multiple components.
Both components work completely as intended when im publishing them in two different projects.
What am i missing here? Thanks in advance!
You don't need to export using the components property, you simply need to do:
export {
Component1,
Component2
}
You would then do:
import {Component1} from 'npm-package';
import {Component2} from 'npm-package';
or
import {Component1, Component2} from 'npm-package';
see: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
I'm trying to build this package:
https://github.com/searchkit/searchkit/ (version v0.10.1)
with webpack and use this with my modules:
node v6.1.0
npm v3.8.6
Build strategy:
fetch repository from github
npm install
npm run build
inside /node_modules/
nothing special is done.
But after trying to use this module withun my components I get those cases.
Case is that if I build with:
searchkit/src/core/react/SearchkitProvider.tsx
import * as React from "react";
import {SearchkitManager} from "../SearchkitManager"
export interface SearchkitProps {
searchkit:SearchkitManager
children?:any
}
export class SearchkitProvider extends React.Component<SearchkitProps,any> {
static childContextTypes = {
searchkit:React.PropTypes.instanceOf(SearchkitManager)
}
static propTypes = {
searchkit:React.PropTypes.instanceOf(SearchkitManager).isRequired,
children:React.PropTypes.element.isRequired
}
componentWillMount() {
this.props.searchkit.setupListeners()
}
componentDidMount(){
this.props.searchkit.completeRegistration()
}
componentWillUnmount(){
this.props.searchkit.unlistenHistory()
}
getChildContext(){
return {searchkit:this.props.searchkit}
}
render(){
return (
<div>IT DOES WORK!!</div>
);
}
}
using by
class Listing extends React.Component {
render() {
return (
<div>
<SearchkitProvider searchkit={searchkit}>
<div></div>
</SearchkitProvider>
</div>
);
}
}
It DOES work properly with proper response, but If I change module's source to:
export class SearchkitProvider extends React.Component<SearchkitProps,any> {
(...)
render(){
return (
<div><input ref="REF" /></div>
);
}
}
it throws this error Uncaught Error: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded.
I'm not really sure what dependency is made while I'm doing that kind of change ? Should I look for duplicated React instances even though it's working when I'm not using input with ref ?
Webpack.config.js:
const path = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const copyrightBanner = require("fs").readFileSync("./COPYRIGHT", "utf-8")
const autoprefixer = require('autoprefixer')
module.exports = {
entry: {
"ignore":['./theming/index.ts'],
"bundle":['./src/index.ts']
},
output: {
path: path.join(__dirname, 'release'),
filename: '[name].js',
library:["Searchkit"],
libraryTarget:"umd",
publicPath: '',
css: 'theme.css'
},
resolve: {
extensions:[".js", ".ts", ".tsx","", ".webpack.js", ".web.js", ".scss"],
alias: { react: path.resolve('../react') }
},
postcss: function () {
return [autoprefixer]
},
plugins: [
new webpack.BannerPlugin(copyrightBanner, {entryOnly:true}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new ExtractTextPlugin("theme.css", {allChunks:true}),
new webpack.optimize.UglifyJsPlugin({
mangle: {
except: ['require', 'export', '$super']
},
compress: {
warnings: false,
sequences: true,
dead_code: true,
conditionals: true,
booleans: true,
unused: true,
if_return: true,
join_vars: true,
drop_console: true
}
})
],
externals: {
"react": "React",
"react-dom":"ReactDOM"
},
module: {
loaders: [
{
test: /\.tsx?$/,
loaders: ['ts'],
include: [path.join(__dirname, 'src'),path.join(__dirname, 'theming')]
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract(require.resolve("style-loader"),require.resolve("css-loader")+"!"+require.resolve("postcss-loader")+"!"+require.resolve("sass-loader")),
include: path.join(__dirname, 'theming')
},
{
test: /\.(jpg|png|svg)$/,
loaders: [
'file-loader?name=[path][name].[ext]'
],
include: path.join(__dirname, 'theming')
}
]
}
};
npm ls react:
├── react#0.14.8
└─┬ UNMET PEER DEPENDENCY searchkit#0.10.1
└── react#0.14.8
npm ERR! peer dep missing: searchkit#0.9.x, required by searchkit-multiselect#0.0.1