I am running an easy Sharepoint Framework project in Visual Studio Code:
I have this structure:
My files are as follows:
ComplexCalculator.ts
export class ComplexCalculator {
public sqr(v1: number): number {
return v1*v1;
}
public multiply(v1:number, v2:number): number {
return v1*v2;
}
}
EasyCalculator.ts
export class EasyCalculator {
public sum(v1: number, v2: number): number {
return v1 + v2;
}
public subtraction(v1: number, v2: number): number {
return v1 - v2;
}
}
Calculator.ts
export * from './ComplexCalculator';
export * from './EasyCalculator';
Calculator.manifest.json
{
"$schema": "../../../node_modules/#microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
"id": "8de800b0-6a4f-4cb0-bf75-62c32e6ea66b",
"componentType": "Library",
"version": "0.0.1",
"manifestVersion": 2
}
On my config.json I have this:
{
"entries": [
{
"entry": "./lib/webparts/librarysample/LibrarysampleWebPart.js",
"manifest": "./src/webparts/librarysample/LibrarysampleWebPart.manifest.json",
"outputPath": "./dist/librarysample.bundle.js"
},
{
"entry": "./lib/libraries/calculator/Calculator.js",
"manifest": "./src/libraries/calculator/Calculator.manifest.json",
"outputPath": "./dist/calculator.bundle.js"
}
],
"externals": {
"#microsoft/sp-client-base": "node_modules/#microsoft/sp-client-base/dist/sp-client-base.js",
"#microsoft/sp-client-preview": "node_modules/#microsoft/sp-client-preview/dist/sp-client-preview.js",
"#microsoft/sp-lodash-subset": "node_modules/#microsoft/sp-lodash-subset/dist/sp-lodash-subset.js",
"office-ui-fabric-react": "node_modules/office-ui-fabric-react/dist/office-ui-fabric-react.js",
"react": "node_modules/react/dist/react.min.js",
"react-dom": "node_modules/react-dom/dist/react-dom.min.js",
"react-dom/server": "node_modules/react-dom/dist/react-dom-server.min.js",
"calculator": "./dist/calculator.bundle.js"
},
"localizedResources": {
"librarysampleStrings": "webparts/librarysample/loc/{locale}.js"
}
}
and finally on my gulpfile.js
const gulp = require('gulp');
const build = require('#microsoft/sp-build-web');
var through = require('through2'),
util = require('gulp-util'),
spawn = require('child_process').spawn,
clean = require('gulp-clean'),
ts = require('gulp-typescript');
build.initialize(gulp);
var libsPath = 'lib/libraries';
var srcPath = 'src/libraries';
var calculatorLibraryFolder = 'calculator';
gulp.task('watch-calculator-lib', (cb) => {
var watcher = gulp.watch(`${srcPath}/${calculatorLibraryFolder}/**/*.ts`, ['update-calculator-typings']);
watcher.on('change', (event) => {
console.log(`File ${event.path} was ${event.type}, Rebuilding library typings...`);
});
});
gulp.task('update-calculator-typings', [
'update-calculator-typings:clean-old-typings',
'update-calculator-typings:get-latest-typings',
'update-calculator-typings:build-lib-typings'
], () => {
});
gulp.task('update-calculator-typings:clean-old-typings', () => {
return gulp.src(`${libsPath}/${calculatorLibraryFolder}/**`, { read: false })
.pipe(clean());
});
gulp.task('update-calculator-typings:get-latest-typings', ['update-calculator-typings:clean-old-typings'], () => {
var tsResult = gulp.src(`${srcPath}/${calculatorLibraryFolder}/**/*.ts`)
.pipe(ts({
outDir: `${libsPath}/${calculatorLibraryFolder}`,
module: 'umd',
declaration: true
}));
return tsResult.dts.pipe(gulp.dest(`${libsPath}/${calculatorLibraryFolder}`));
});
gulp.task('update-calculator-typings:build-lib-typings', ['update-calculator-typings:get-latest-typings'], () => {
return gulp.src(`${libsPath}/${calculatorLibraryFolder}/**/*.d.ts`)
.pipe(updateLibTypings('calculator.d.ts'))
.pipe(gulp.dest('./typings'));
});
var updateLibTypings = function (typingsFilePath, opt) {
var typings = ["declare module 'calculator' {"];
var latestFile;
function processTypings(file, encoding, cb) {
if (file.isNull() || file.isStream()) {
cb();
return;
}
latestFile = file;
var contents = file.contents.toString('utf8');
if (contents.indexOf('export declare class ') === -1) {
cb();
return;
}
contents = contents.replace('export declare class ', 'class ');
typings.push(contents);
cb();
}
function endStream(cb) {
if (!latestFile) {
cb();
return;
}
typings.push('}');
var file = latestFile.clone({ contents: false });
file.path = latestFile.base + typingsFilePath;
file.contents = new Buffer(typings.join('\r\n'));
this.push(file)
cb();
}
return through.obj(processTypings, endStream);
}
the typings file is generated correctly on the dist folder
calculator.d.ts
declare module 'calculator' {
class ComplexCalculator {
sqr(v1: number): number;
multiply(v1: number, v2: number): number;
}
class EasyCalculator {
sum(v1: number, v2: number): number;
subtraction(v1: number, v2: number): number;
}
}
However, when I try to reference it into my webpart file
import * as calculator from 'calculator';
and then I try to compile
I get this error
Error - typescript - src/webparts/librarysample/LibrarysampleWebPart.ts(13,29): error TS2307: Cannot find module 'calculator'.
Your code import * as calculator from 'calculator'; is wrong. You need to import modules in your project using relative paths. e.g.
import * as calculator from './path/to/Calculator';
More
Be careful about file casing. I prefer camelCase for consistency.
Master node_modules : https://nodejs.org/docs/latest/api/modules.html
Related
I am integrating Vite SSR to existing vue project. I copied vite configuration from SSR playground project and bumped ionic version to 6 because of dynamic loading issue from stencil.
After upgrading, it isn't compiling, showing this error.
12:03:15 AM [vite] Error when evaluating SSR module /src/components/ImportType.vue:
/data/Work/ssr-vue/node_modules/#ionic/core/components/ion-accordion.js:4
import { proxyCustomElement, HTMLElement, h, Host } from '#stencil/core/internal/client';
^^^^^^
SyntaxError: Cannot use import statement outside a module
Here is my vite.config.js file
const vuePlugin = require('#vitejs/plugin-vue')
const vueJsx = require('#vitejs/plugin-vue-jsx')
const virtualFile = '#virtual-file'
const virtualId = '\0' + virtualFile
const nestedVirtualFile = '#nested-virtual-file'
const nestedVirtualId = '\0' + nestedVirtualFile
/**
* #type {import('vite').UserConfig}
*/
module.exports = {
plugins: [
vuePlugin(),
vueJsx(),
{
name: 'virtual',
resolveId(id) {
if (id === '#foo') {
return id
}
},
load(id) {
if (id === '#foo') {
return `export default { msg: 'hi' }`
}
}
},
{
name: 'virtual-module',
resolveId(id) {
if (id === virtualFile) {
return virtualId
} else if (id === nestedVirtualFile) {
return nestedVirtualId
}
},
load(id) {
if (id === virtualId) {
return `export { msg } from "#nested-virtual-file";`
} else if (id === nestedVirtualId) {
return `export const msg = "[success] from conventional virtual file"`
}
}
}
],
ssr: {
external: ["npm: #ionic/vue"]
},
build: {
minify: false
}
}
Please help me.
I'm using Webpack for a project (and I'm starting to regret that) and tree shaking is not working.
I created a simple test library which I bundle using Rollup since Webpack cannot generate esm libraries (see here for more info about that: https://github.com/webpack/webpack/issues/2933).
Here is the content of my library (which uses Typescript):
export class Test1 {
addOne(x: number) {
console.log('addOne');
return x + 1;
}
}
export class Test2 {
addTwo(x: number) {
console.log('addTwo');
return x + 2;
}
}
Once I bundle it with Rollup, I get this:
var n = function () {
function n() {}
return n.prototype.addOne = function (n) {
return console.log("addOne"), n + 1
}, n
}(),
o = function () {
function n() {}
return n.prototype.addTwo = function (n) {
return console.log("addTwo"), n + 2
}, n
}();
export {
n as Test1, o as Test2
};
Then, I use webpack to bundle my test app that is using this library. Here is the code of the app:
'use strict';
import { Test1 } from './test.esm';
const f = new Test1();
console.log(f.addOne(1));
Once I look at the generated bundle, the Test2 code is tree shaken and does not appear in the bundle.
So far, so good.
If then I add a new function to my Test2 class, like this:
export class Test1 {
addOne(x: number) {
console.log('addOne');
return x + 1;
}
}
export class Test2 {
addTwo(x: number) {
console.log('addTwo');
return x + 2;
}
addThree(x: number) {
console.log('addThree');
return x + 3;
}
}
I get the following output from Rollup:
var o = function () {
function o() {}
return o.prototype.addOne = function (o) {
return console.log("addOne"), o + 1
}, o
}(),
n = function () {
function o() {}
return o.prototype.addTwo = function (o) {
return console.log("addTwo"), o + 2
}, o.prototype.addThree = function (o) {
return console.log("addThree"), o + 3
}, o
}();
export {
o as Test1, n as Test2
};
If then I generate my app bundle with webpack and this new library, without changing anything to the code of the app using the lib, the content of Test2 is added to the output.
What am I doing wrong here?
I'm using webpack 5.12.3.
My webpack config is:
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
resolve: {
fallback: {
'fs': false,
}
},
entry: {
'sample-face': './src/sample-face.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin({
patterns: [
{ from: 'src/index.html', to: path.resolve(__dirname, 'dist') },
{ from: 'src/sample-face.html', to: path.resolve(__dirname, 'dist') },
{ from: 'src/assets', to: path.resolve(__dirname, 'dist/assets') },
]
})
]
};
I have a project written for browser using AMD modules, now I need to run the same code in nodejs, so I need to rewrite each file into using CommonJs modules instead. I tried webpack, but it gives me a bundle which I don't need. All I want is to keep my files like they are but rewrite define(.. imports to require(..)
thank to Felix Kling's advice i wrote the following transformer in typescript
import { FileInfo, API, Options } from 'jscodeshift';
import { resolve, normalize, relative } from 'path';
export default function transformer(file: FileInfo, api: API, options: Options) {
const { j } = api;
return j(file.source)
.find(j.ExpressionStatement, { expression: { callee: { name: 'define' } } })
.replaceWith(({ node }) => {
const { expression: defineCallExpression } = node;
if (defineCallExpression.type !== 'CallExpression') return crash('No call to define function of AMD.');
const [moduleLocationsArray, callback] = defineCallExpression.arguments;
if (callback.type !== 'FunctionExpression') return;
if (moduleLocationsArray.type !== 'ArrayExpression') return;
const imports = moduleLocationsArray.elements.map((element, index) => {
if (element === null) return crash('Module name skipped.');
if (element.type !== 'Literal') return crash('Module name is not a literal');
const param = callback.params[index];
if (param.type !== 'Identifier') return crash('Module parameter is not an identifier.');
return {
location: element.value as string,
name: param.name,
};
}).filter(pair => shouldKeepModule(pair.location));
const filePath = normalize(resolve(__dirname, file.path));
const baseDir = normalize(resolve(__dirname, options.where));
const importStatements = imports.map(({name, location}) => {
const modulePath = normalize(resolve(baseDir, location));
const relativeModuleName = slashings(relative(filePath, modulePath));
const text = `const ${name} = require('${relativeModuleName}');`;
const statement = api.j(text, options);
return statement;
});
const statementsBefore = callback.body.body;
const statementsAfter = [...importStatements, ...statementsBefore];
return statementsAfter;
})
.toSource();
}
function shouldKeepModule(location: string): boolean {
return location !== 'module' && location !== 'exports' && location !== 'require';
}
function crash(message: string): never { throw new Error(message); }
function slashings(text: string): string { return text.replace(/\\/g, '/'); }
with the following tsconfig.json
{
"compileOnSave": true,
"compilerOptions": {
"strict": true,
"target": "es6",
"module": "commonjs",
"lib": ["es6"],
"types": ["node", "jscodeshift"],
"outDir": "../../node_modules/amd-to-commonjs"
}
}
with the following package.json
{
"private": true,
"devDependencies": {
"#types/node": "7.0.4",
"#types/jscodeshift": "0.6.0",
"jscodeshift": "0.6.3",
"typescript": "3.4.0-dev.20190227"
}
}
built by the following command
npm install
node ../../node_modules/typescript/bin/tsc --project ./
and run by the following command
node ../../node_modules/jscodeshift/bin/jscodeshift.js --transform=../../node_modules/amd-to-commonjs/transformer.js --where=../../scripts/built ../../scripts/built
I am trying to get object from api.json but it throws error , based on typescript i have added declare module "*.json" into the project , Any idea how can i achieve this task ?
api.json
{
"Refills": {
"getPatientInfo": "Refills/patientInfo/GetPatientInfo"
}
}
index.ts
import {ModuleExecutor} from "./common/ModuleExecutor";
import {Identity} from "./common/Enums";
export class Index {
private executor: ModuleExecutor = null;
// Any string prepended with # is handled by grunt before building the project
// grunt dynamically reads the config/api.json and loads only the apis that are listed there
// api.json consists of the API name and the folder path for grunt
private _apisConfig: string = '#api'
constructor(identity: string) {
this.executor = new ModuleExecutor(Identity[identity]);
const apiConfig = JSON.parse(this._apisConfig);
console.log('API', apiConfig);
for (const module in apiConfig) {
if (apiConfig.hasOwnProperty(module)) {
this[module] = {};
for (const api in apiConfig[module]) {
if (apiConfig[module].hasOwnProperty(api)) {
this[module][api] = this.executor.execute(apiConfig[module][api]);
}
}
}
}
}
}
Error
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
Compiled index.js file
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ModuleExecutor_1 = require("./common/ModuleExecutor");
const Enums_1 = require("./common/Enums");
class Index {
constructor(identity) {
this.executor = null;
this._apisConfig = '';
this.executor = new ModuleExecutor_1.ModuleExecutor(Enums_1.Identity[identity]);
const apiConfig = JSON.parse(this._apisConfig);
console.log('API', apiConfig);
for (const module in apiConfig) {
if (apiConfig.hasOwnProperty(module)) {
this[module] = {};
for (const api in apiConfig[module]) {
if (apiConfig[module].hasOwnProperty(api)) {
this[module][api] = this.executor.execute(apiConfig[module][api]);
}
}
}
}
}
}
exports.Index = Index;
//# sourceMappingURL=index.js.map
I have a sharepoint framework project with the following folder structure:
It has a library called dataaccess and a webpart factory method
Sharepointdataprovider.ts file
import {
SPHttpClient,
SPHttpClientBatch,
SPHttpClientResponse
} from '#microsoft/sp-http';
import { IWebPartContext } from '#microsoft/sp-webpart-base';
import List from '../models/List';
import IDataProvider from './IDataProvider';
export default class SharePointDataProvider implements IDataProvider {
private _selectedList: List;
private _lists: List[];
private _listsUrl: string;
private _listItemsUrl: string;
private _webPartContext: IWebPartContext;
public set selectedList(value: List) {
this._selectedList = value;
this._listItemsUrl = `${this._listsUrl}(guid'${value.Id}')/items`;
}
public get selectedList(): List {
return this._selectedList;
}
public set webPartContext(value: IWebPartContext) {
this._webPartContext = value;
this._listsUrl = `${this._webPartContext.pageContext.web.absoluteUrl}/_api/web/lists`;
}
public get webPartContext(): IWebPartContext {
return this._webPartContext;
}
public getLists(): Promise<List[]> {
const listTemplateId: string = '171';
const queryString: string = `?$filter=BaseTemplate eq ${listTemplateId}`;
const queryUrl: string = this._listsUrl + queryString;
return this._webPartContext.spHttpClient.get(queryUrl, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
})
.then((json: { value: List[] }) => {
return this._lists = json.value;
});
}
}
In my gulpfile.js I have this:
'use strict';
const gulp = require('gulp');
const build = require('#microsoft/sp-build-web');
//Required libraries to update typings
var through = require('through2'),
util = require('gulp-util'),
spawn = require('child_process').spawn,
clean = require('gulp-clean'),
ts = require('gulp-typescript');
//ootb
build.initialize(gulp);
// required variables to make configuration easier on the gulp tasks below
var libsPath = 'lib/libraries';
var srcPath = 'src/libraries';
var spdataaccessLibraryFolder = 'spdataaccess';
gulp.task('watch-spdataaccess-lib', (cb) => {
var watcher = gulp.watch(`${srcPath}/${spdataaccessLibraryFolder}/**/*.ts`, ['update-spdataaccess-typings']);
watcher.on('change', (event) => {
console.log(`File ${event.path} was ${event.type}, Rebuilding library typings...`);
});
});
gulp.task('update-spdataaccess-typings', [
'update-spdataaccess-typings:clean-old-typings',
'update-spdataaccess-typings:get-latest-typings',
'update-spdataaccess-typings:build-lib-typings'
], () => {
});
gulp.task('update-spdataaccess-typings:clean-old-typings', () => {
return gulp.src(`${libsPath}/${spdataaccessLibraryFolder}/**`, { read: false })
.pipe(clean());
});
gulp.task('update-spdataaccess-typings:get-latest-typings', ['update-spdataaccess-typings:clean-old-typings'], () => {
var tsResult = gulp.src(`${srcPath}/${spdataaccessLibraryFolder}/**/*.ts`)
.pipe(ts({
outDir: `${libsPath}/${spdataaccessLibraryFolder}`,
module: 'umd',
declaration: true
}));
return tsResult.dts.pipe(gulp.dest(`${libsPath}/${spdataaccessLibraryFolder}`));
});
gulp.task('update-spdataaccess-typings:build-lib-typings', ['update-spdataaccess-typings:get-latest-typings'], () => {
return gulp.src(`${libsPath}/${spdataaccessLibraryFolder}/**/*.d.ts`)
.pipe(updateLibTypings('spdataaccessLibrary.d.ts'))
.pipe(gulp.dest('./typings'));
});
var updateLibTypings = function (typingsFilePath, opt) {
var typings = ["declare module 'spdataaccess' {"];
var latestFile;
function processTypings(file, encoding, cb) {
if (file.isNull() || file.isStream()) {
cb();
return;
}
latestFile = file;
var contents = file.contents.toString('utf8');
if (contents.indexOf('export declare class ') === -1) {
cb();
return;
}
contents = contents.replace('export declare class ', 'class ');
typings.push(contents);
cb();
}
function endStream(cb) {
if (!latestFile) {
cb();
return;
}
typings.push('}');
var file = latestFile.clone({ contents: false });
file.path = latestFile.base + typingsFilePath;
file.contents = new Buffer(typings.join('\r\n'));
this.push(file)
cb();
}
return through.obj(processTypings, endStream);
}
However when I try to run:
gulp update-spdataaccess-typings
I get these errors:
error TS2307: Cannot find module '#microsoft/sp-webpart-base'.
If I check tsconfig.json, it seems to be fine
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"types": [
"es6-promise",
"es6-collections",
"webpack-env"
]
}
}
I had the same error today when I set up SharePoint framework.
You need to use the following command:
npm install #microsoft/sp-webpart-base