The scenario is that I'm developing a component for use by a website and want to combine the files that I've created into one index.js for ease of use.
File index.jsx includes the line var header = require('./header.jsx'); and header.jsx includes the line var React = require('react'); where React has been added as an npm module.
If I use webpack --module-bind jsx --entry .\src\index.jsx --output-file .\dist\index.js on the command line this produces a large file with React source included.
Is there a way that I can have just my index.jsx and header.jsx transformed and concatenated?
You can mark React as an external to achieve that. Ie.
externals: {
react: 'react',
}
Related
I am trying to use a vue component library, which is loaded by a script tag, within a vue application. That component library is using a webpack setup and uses the setting externals to exclude all vue dependencies. So the host bundle which is using that library has to ship vue and other needed dependencies.
The component library itself is using vue cli with the script vue-cli-service build --target lib to build a lib.umd.js file. Inside the index.html of my host bundle I am just including that file by a script tag. The webpack setup of the host bundle uses config.externals(['#test/my-component-library']) to exclude the component library which is being loaded externally. Inside the host bundle I am using the component library like this:
import { MyComponent } from '#test/my-component-library'
When I run my application, I get the following error: Uncaught SyntaxError: Invalid or unexpected token. This error happens in the following line of my host bundle:
/*!*******************************************************!*\
!*** external "#test/my-component-library" ***!
\*******************************************************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("module.exports = #test/my-component-library;//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQHRlc3QvbXktY29tcG9uZW50LWxpYnJhcnkuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vZXh0ZXJuYWwgXCJAdGVzdC9teS1jb21wb25lbnQtbGlicmFyeVwiPzFjOTAiXSwic291cmNlc0NvbnRlbnQiOlsibW9kdWxlLmV4cG9ydHMgPSBAdGVzdC9teS1jb21wb25lbnQtbGlicmFyeTsiXSwibWFwcGluZ3MiOiJBQUFBIiwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///#test/my-component-library\n");
/***/ })
Does anyone know why webpack is producing such code and how I can correct it?
I guess I found the solution. So first of all I had a wrong configuration for externals. The correct configuration is:
config.externals({
'#test/my-component-library': {
root: '#test/my-component-library',
commonjs2: '#test/my-component-library',
commonjs: '#test/my-component-library',
amd: '#test/my-component-library',
},
})
In the component library I had to add the webpack configuration config.output.library('MyComponentLibrary') so that the object MyComponentLibrary is globally available in window scope. Then I had to remove the import statement in the host bundle. To register the component I had to add this line to my vue file:
components: {
'MyComponent': MyComponentLibrary.MyComponent,
}
But now I have another problem. The component library itself is using vuetify (which is another component library). But I have also added vuetify to the externals option because my host bundle already contains vuetify. And now I am getting lots of Unknown custom element exceptions. So apparently my component library does not find the vuetify components in my host bundle. Are there any solutions for this problem?
I create my react npm package using webpack but when i install my npm package to my react project, package styles are not apply on classes. Why this happens
Here is the link of npm package. You can install 0.0.5 version. In my webpack i used style-loader but it shows me document is not defined errors but if enable following line
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
Document not defined error resolved but styles not apply on classes in react project
Here is webpack file image
Here is package.json file image
Here is Test.jsx file image
Here is the main.css build file image which webpacks generates
Here is the test.js build file image which webpacks generates
Here is test.scss file image
Your webpack is working fine. You just need to import your styles manually from your build. This usually has to be done for all packages which define styles.
For ReactStrap you have to add this for styles
import 'bootstrap/dist/css/bootstrap.min.css';
For AntDesign you need this
import 'antd/dist/antd.css';
Same way you need to take import your styles from your build. i.e
import "#afiniti/test/build/main.css";
And your styles would start working.
Example code
import Test from "#afiniti/test";
import "#afiniti/test/build/main.css";
export default function App() {
return (
<Test />
}
Here is a link to a simplified working codesandbox. Good Luck!
I am currently testing stencil js. For now I want to write stencil components and include them within a VUE/React project. The official website of stencil already shows how to integrate them within a framework (https://stenciljs.com/docs/overview). But they assume that your own stencil component library has already been published to npm.
Is there a way to integrate stencil components locally into a framework to test them without publishing them first?
Yes, you can use npm-link for that.
cd my-component-lib
npm link
cd ../my-app
npm link my-component-lib # or whatever you have named the project in package.json
If you have any problems with that (e. g. with paths not resolving properly), you can also try to pack your package and install the packed version instead, using npm-pack:
cd my-component-lib
npm pack
cd ../my-app
npm install ../my-component-lib/my-component-lib-1.0.0.tgz
Linking is preferable though because changes to your component library will be reflected immediately (after a rebuild), whereas with packing you'd have to re-pack and re-install it after every change to your lib.
Instead of publishing or packing your packages, you could utilize TypeScript's path mapping feature.
This allows you to write your import statements just as you would with a published package, but behind the scenes TypeScript maps the imports to their given source code location.
Here's an example of a tsconfig.json with path mapping added to the compiler options:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"ui-components": ["libs/ui-components"],
"ui-components/loader": ["libs/ui-components/dist/loader/index.cjs.js"],
"ui-components-react": ["generated/ui-components-react/src/components.ts"]
},
...
As you can see, it has 3 mappings: the path to the core Stencil components ui-components, the path to the generated React components which are exposed as ui-components-react, as well as the generated loader ui-components/loader which provides the bridge between the Custom elements and the React wrappers.
I created a full working example for Stencil Web Components with generated bindings and wrappers for React that comes without the need of publishing any package: Nx Stencil React.
Please note that this answer is based on #stencil/core 1.14.0 or below. Future versions may have a different approach on generating the framework integrations.
I've had quite a bit of trouble with this myself so will provide an answer specifically for Vue 3 as Stencil's Framework Integrations guide seems to refer only to Vue 2.
Starting Projects
Stencil Component
Following the Getting Started guide run npm init stencil. Choose the component option.
There was a bug in v2.7.0 so I update to v2.8.0 with npm i #stencil/core#latest --save-exact
Build the project with npm run build
Optional
By default, the stencil project configures multiple build targets, to make it easier to see what build files are being used you can edit the stencil config to only include the custom elements bundle:
\\ stencil.config.ts
outputTargets: [
{
type: 'dist-custom-elements-bundle',
},
{
type: 'dist',
esmLoaderPath: '../loader',
},
],
You also need the 'dist' type for the .d.ts typings file to be generated with your custom-elements (not sure why).
Vue 3 App
Using a globally installed Vue CLI #vue/cli#4.5.13 create a new Vue 3 default project.
Using Stencil in Vue 3
Install your stencil component project
npm install --save ../<path>/stencil-component as a dependency of your vue app.
Fixing NPM Module Resolution
Following the Vue CLI - Troubleshooting guide add a vue.config.js file to the root of your Vue 3 project with the line config.resolve.symlinks(false),
Skipping Component Resolution
In the same file we need to configure Using Custom Elements in View
\\ vue.config.js
module.exports = {
chainWebpack: (config) => {
config.resolve.symlinks(false),
config.module
.rule("vue")
.use("vue-loader")
.tap((options) => ({
...options,
compilerOptions: {
isCustomElement: (tag) => tag.includes("my-"),
},
}));
},
};
Framework Integration
Now we can declare the custom elements, but in the Vue 3 way
\\ main.js
import { createApp } from 'vue'
import App from './App.vue'
import { defineCustomElements } from "stencil-component";
defineCustomElements();
createApp(App).mount('#app');
You can now use your custom component as normal. Here's what my App.vue file looked like after hacking the example starter code:
<template>
<my-component first="Andy" middle="2K" last="11"></my-component>
</template>
<script>
import { MyComponent } from "stencil-component";
export default {
name: 'App',
components: {
MyComponent
}
}
</script>
Errors
No ESLint Config
No ESLint configuration found in /<path>/stencil-component/dist/custom-elements.
Fixed by telling webpack not to resolve symlinks in vue.config.js
Uncaught TypeError: class constructors must be invoked with 'new'
This error occurs in the browser after a successful compilation.
Resolved by telling webpack / vue not to resolve your custom components
Custom Component Not Visible
There are no errors and your component is showing in the DOM inspector but not appearing on the page.
You need to defineCustomElements() in main.js.
Component not found
I've had some variation of this error when trying to import and use my component but haven't been able to reproduce it just now. Doing all of the above and restarting the dev server works fine for me.
For local integration, you can reference the esm.js file inside www/build folder which can be used in the head tag of the Vue/React project.
For eg if you have the below 2 apps
stencil-components - stencil components
stencil-react - sample react app which will consume the components.
Once you run stencil-components by npm run start it will be hosted at 3333 (by default).
Including below line in head ofindex.html of stencil-react will integrate components with live reloading on change.
<script type="module" src="http://localhost:3333/build/stencil-components.esm.js"></script>
Following import statement pulls entire router module into the final webpack bundle.
import { DefaultUrlSerializer } from '#angular/router';
Is there a way to just import the DefaultUrlSerializer without other irrelevant module ?
I'm using Webpack module builder and Angular Cli for AOT/production builds.
No, you cannot do that unless you build the Angular yourself. The npm package doesn't ship modules separately, but as a one bundle in the UMD format:
node_modules
#angular
router
bundles
router.umd.js
No matter how you import DefaultUrlSerializer, webpack will include the contents of the entire router.umd.js in the final build as it can't extract code from a file.
I would like to use the dat.GUI library for a project that's build with Webpack 2. If I install the module via npm -install --save-dev dat.gui and then try to import it using import * as DAT from 'dat.gui'; I get the following error when Webpack is trying to compile my project:
ERROR in ./~/dat.gui/src/dat/controllers/NumberControllerSlider.js
Module not found: Error: Can't resolve 'style' in
'/home/me/myProject/node_modules/dat.gui/src/dat/controllers'
BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix
when using loaders.
I know this error occurs when using Webpack 2 to build Webpack 1 based projects. But why is Webpack even trying to build the module if there already is a build version inside node_modules/dat.gui/build';? Is there a way to tell Webpack or NPM to use the existing build version without trying to re-build it?
When importing a node module, webpack looks into its package.json and uses the main field as entry of the module, similar to what Node.js does (webpack looks for more fields by default, see resolve.mainFields).
Since for dat.gui the main field does not point to the built version but to the source, which actually inlines loaders as seen in dat.gui#0.6.1 - NumberControllerSlider.js for the styleSheet import, and that is not a good idea in general and certainly not to publish.
But you can import the built version by specifying the corresponding path. So your import would be:
import * as DAT from 'dat.gui/build/dat.gui.js';
If you'd like to still import just dat.gui you can configure resolve.alias to point to the built version as follows:
resolve: {
alias: {
'dat.gui': 'dat.gui/build/dat.gui.js'
}
}
With that you can use your original import statement:
import * as DAT from 'dat.gui';