I'm using the vue-sfc-rollup lib to create a lib for Vue, so far it's ok, my lib is working, and I can use it in other projects, however, a doubt has arisen.
In which file could I add in my lib the use of bootstrap? to understand better I'm putting below the structure that the SFC generated for me..
The file entry.js
// iife/cjs usage extends esm default export - so import it all
import plugin, * as components from '#/entry.esm';
// Attach named exports directly to plugin. IIFE/CJS will
// only expose one global var, with component exports exposed as properties of
// that global var (eg. plugin.component)
Object.entries(components).forEach(([componentName, component]) => {
if (componentName !== 'default') {
plugin[componentName] = component;
}
});
export default plugin;
the file entry.esm.js
// Import vue components
import * as components from '#/lib-components/index';
// install function executed by Vue.use()
const install = function installZicketVueCheckout(Vue) {
Object.entries(components).forEach(([componentName, component]) => {
Vue.component(componentName, component);
});
};
// Create module definition for Vue.use()
export default install;
// To allow individual component use, export components
// each can be registered via Vue.component()
export * from '#/lib-components/index';
Related
In my Nuxt project, I created a custom plugin file that returns an object. /helpers/settings:
export const settings = {
baseURL: 'https://my-site.com',
...
};
I register this file in /plugins/settings.ts:
import Vue from 'vue';
import { settings } from '~/helpers/settings';
Vue.prototype.$settings = settings;
And in nuxt.config.js:
export default {
...
plugins: [
'~/plugins/settings',
Then, in a component, I can use my plugin like so:
export default Vue.extend({
data() {
return {
url: `${this.$settings.baseURL}/some-path`,
Everything works as expected, except in that in my console, I get a typescript error from the line that I refer to my plugin in my component:
Property '$settings' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, unknown, Readonly<Record<never, any>>>'.
Hence my question: what is the proper way to apply a type to my custom plugin so that I don't get this error every time I use it?
According to the docs, you'll need to augment the type file for Vue.
Place the following code in a file named plugin-types.d.ts.
// 1. Make sure to import 'vue' before declaring augmented types
import Vue from 'vue'
// 2. Specify a file with the types you want to augment
// Vue has the constructor type in types/vue.d.ts
declare module 'vue/types/vue' {
// 3. Declare augmentation for Vue
interface Vue {
$settings: string
}
}
This answer also work but I found an easier, though dirtier, way to fix it without the need of adding the plugin-types.d.ts file.
Just add a property to you componen with the name of plugin like following:
#Component
export default class YourComponent extends Vue {
private $settings!: string; // your plugin here
private url: string = `${this.$settings.baseURL}/some-path`
}
See question title. I found a great reference for the forms of export available, but I have not seen what I'm looking for.
Is it possible to do something like the following?
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
export * as Constants from './constants.js';
I.e. this would provide a named export Constants inside of index.js containing all of the named exports from constants.js.
This answer seems to indicate it's not possible in TypeScript; is the same true for pure JavaScript?
(This example is a bit contrived; in reality I'm trying to have a prop-types.js module that uses named exports for internal use within the React package, but also exports the prop type definitions under PropTypes for external consumption. I tried to simplify for the sake of the question.)
No, it's not allowed in JS either, however there is a proposal to add it. For now, just use the two-step process with importing into a local variable and exporting that:
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
import * as Constants from './constants.js';
export {Constants};
Today in 2019, it is now possible.
export * as name1 from …;
The proposal for this spec has merged to ecma262. If you're looking for this functionality in an environment that is running a previous JS, there's a babel plugin for it! After configuring the plugin (or if you're using ecma262 or later), you are able to run the JS in your question:
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
export * as Constants from './constants.js';
// file: component.js
import { Constants } from './index.js';
const newVar = Constants.SomeConstant1; // 'yay'
// file: index.js
// note, this doesn't have to be at the top, you can put it wherever you prefer
import * as AllExportsFromThisModule from "./index.js"; // point this at the SAME file
export default AllExportsFromThisModule;
export const SOME_CONSTANT = 'yay';
export const SOME_OTHER_CONSTANT = 'yayayaya';
I am trying to create manual mocks for the #material-ui/core/styles module, which exports the HOC called withStyles.
Using the inline mock with jest.mock works perfectly, but when I try to move this logic into sharable __mocks__ folder, it does not work anymore.
I removed from the file being tested all the unecessary code, just keeping the two lines creating the issues:
import { withStyles } from '#material-ui/core/styles';
console.log('loaded styles:', withStyles);
export default 'hello';
And the test simplified as well, just to see if the mock is working, is the following:
import test from '../test';
console.log(test);
What I have tried is to create a __mocks__ folder in the root of the project, where I have the node_modules folder.
There I created a first folder called #material-ui and inside it another folder called core.
Inside this folder I have a file called styles.js with the following code:
export const withStyles = 'hello world';
So the structure looks like:
- __mocks__
- #material-ui
- core
- styles.js
- node_modules
This is the code which works, with the mock defined inside the same testing file:
jest.mock('#material-ui/core/styles', () => ({
withStyles: () => Component => props => (
<Component
classes=""
{...props}
/>
),
}));
What is happening with the __mocks__ folder is that, if I do not call any
jest.mock('#material-ui/core/styles');
inside my test file, it uses the real withStyles, so the real module.
No mock at all is being used.
If I use the:
jest.mock('#material-ui/core/styles');
It uses an automatic mock autogenerated by jest (or it looks so), skipping the one I define above.
Just a note about packages, I used CRA for bootstrapping the app and the jest version I currently have is the 20, with the react-scripts version 1.0.17
Thanks to you all for you the help!
Here is how you should use manual mocking in __mocks__/#material-ui/core/styles.js:
// Grab the original exports
import * as Styles from '#material-ui/core/styles';
const mockWithStyles = () => {
console.log('withStyles being mocked'); // this shows that it works
/**
* Note: if you want to mock this return value to be
* different within a test suite then use
* the pattern defined here:
* https://jestjs.io/docs/en/manual-mocks
*/
return () => {}; // your mock function (adjust as needed)
// you can also return the same implementation on certain conditions
// return Styles.makeStyles;
};
module.exports = { ...Styles, withStyles: mockWithStyles };
Here is how I manual mock makeStyles:
// Grab the original exports
// eslint-disable-next-line import/no-extraneous-dependencies
import * as Styles from '#material-ui/core/styles';
import createMuiTheme from '#material-ui/core/styles/createMuiTheme';
import options from '../../../src/themes/options';
const mockMakeStyles = func => {
/**
* Note: if you want to mock this return value to be
* different within a test suite then use
* the pattern defined here:
* https://jestjs.io/docs/en/manual-mocks
*/
/**
* Work around because Shallow rendering does not
* Hook context and some other hook features.
* `makeStyles` accept a function as argument (func)
* and that function accept a theme as argument
* so we can take that same function, passing it as
* parameter to the original makeStyles and
* binding it with our custom theme
*/
const theme = createMuiTheme(options);
return Styles.makeStyles(func.bind(null, theme));
};
module.exports = { ...Styles, makeStyles: mockMakeStyles };
And makeStyles result uses React.useContext, so we have to avoid mocking useContext for makeStyles. Either use mockImplementationOnce if you use React.useContext(...) first in you component, or just filter it out in your test code as:
jest.spyOn(React, 'useContext').mockImplementation(context => {
console.log(context);
// only stub the response if
if (context.displayName === 'MyAppContext') {
return {
auth: {},
lang: 'en',
snackbar: () => {},
};
}
const ActualReact = jest.requireActual('react');
return ActualReact.useContext(context);
});
And on your createContext() call, probably in a store.js, add a displayName (standard), or any other custom property to Identify your context:
const store = React.createContext(initialState);
store.displayName = 'MyAppContext';
The makeStyles context displayName will appear as StylesContext and ThemeContext and their implementation will remain untouched to avoid error.
This fixed all kind of mocking problem with makeStyles. But I haven't use withStyles to know its structure deeply, but similar logic should be applicable.
I created the file src/__mocks__/#material-ui/core/styles.jsx in my project and inside I put:
import * as Styles from '#material-ui/core/styles';
import React from 'react';
const withStyles = () => Component => props => <Component classes={{}} {...props} />;
module.exports = { ...Styles, withStyles };
I have a large third party library that I need to share between two projects. The project has multiple folders with multiple files that contain multiple exports. Instead of importing these modules like this
import {BaseContainer} from '#company/customproject/src/containers/BaseContainer.js'
I would like to do this
import { BaseContainer } from '#company/customproject'
I know I can manually import all the modules into a single index.js file in the base directory but i am wondering if there is an easier way to do not have import them all explicitly
I know I can manually import all the modules into a single index.js file in the base directory but i am wondering if there is an easier way to do not have import them all explicitly
You should really just create an index.js file and import into that whatever you want to export so that you can control what APIs get exported and to not export private APIs.
That said there is an automated tool that generates an index.js automatically for you:
> npm install -g create-index
> create-index ./src
Which will generate an index.js with all the exports.
As the other answer suggests, you should create an index.js within each directory and explicitly export contents
#company/customproject/index.js
import {BaseContainer, SomeOtherContainer} from './src/containers'
export {
BaseContainer,
SomeOtherContainer
}
#company/customproject/src/containers/index.js
import BaseContainer from './BaseContainer'
import SomeOtherContainer from './SomeOtherContainer'
export {
BaseContainer,
SomeOtherContainer
}
Another option to autoload an entire directory is using require and module.exports to export every scanned file, however. You would likely run into conflicts using both ES6 import/export along with module.exports and default export statements.
#company/customproject/index.js
const fs = require('fs')
const modules = {}
fs.readdirSync(__dirname+'/src/containers').forEach(file => {
file = file.replace('.js', '')
modules[file] = require('./src/containers/'+file)
// map default export statement
if (modules[file].default) {
modules[file] = modules[file].default
}
})
module.exports = modules
Then simply use it in any ES5 or ES6 module
const {BaseContainer} = require('#company/customproject')
or
import {BaseContainer} from '#company/customproject'
For the time being, until the library is split into JS frameworks specific repos (React, JQuery, Angular, etc.), I have multiple libraries within one npm module (yes, that right there is an anti-pattern).
But humor me, how do I export one of the libraries without exporting the other? I don't want the jquery module if I'm just using React and there is only one "main" in package.json.
One option would be to import the module via relative directory that is from './node_modules/ui-combined-module/src/react/dist.js';, but that seems rather messy.
For
// Use one of the following in your example code:
// import {react as UILibraryReact} from 'ui-combined-module';
// const Badge = UILibraryReact.Badge;
// import {jquery as UILibraryJquery} from 'ui-combined-module';
// const Badge = UILibraryJquery.Badge;
import * as react from './react/dist';
import * as jquery from './jquery/dist';
module.exports = {
react,
jquery
};
Why not import jquery or react in the code using this module?
import react from 'yourlib'
Or return a function
exports default function (lib) {
if(lib === 'react') return react;
...
}